From 6b35ab03f2b1d9a8391e252414b289e5bc087535 Mon Sep 17 00:00:00 2001 From: Laurent Nguyen Date: Wed, 23 Jun 2021 21:05:52 +0200 Subject: [PATCH] Switch notebook editor from Monaco back to Code Mirror (#901) --- package-lock.json | 88 +++++++++- package.json | 2 +- .../NotebookViewerComponent.tsx | 2 +- src/Explorer/Notebook/NotebookClientV2.ts | 33 ++-- .../NotebookComponent/NotebookComponent.less | 12 +- .../NotebookReadOnlyRenderer.less | 88 ++++++---- .../NotebookReadOnlyRenderer.tsx | 10 +- .../NotebookRenderer/NotebookRenderer.less | 166 ++++++++++-------- .../NotebookRenderer/NotebookRenderer.tsx | 14 +- .../Notebook/notebookClientV2.test.ts | 8 +- 10 files changed, 267 insertions(+), 156 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50cb07343..12fc5a409 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3709,14 +3709,84 @@ } }, "@nteract/editor": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/@nteract/editor/-/editor-10.1.2.tgz", - "integrity": "sha512-Wtj0kJUSoBZsWUh82JGt6miqYS0jt0k+3SD3cnW9socayxp2KB0Qbqhh2NtrF9ysxVHWnQT8iUarJjpGIdNyng==", + "version": "10.1.12", + "resolved": "https://registry.npmjs.org/@nteract/editor/-/editor-10.1.12.tgz", + "integrity": "sha512-bsUrCctukjWdpKNWQOQmhfxMCQ/SBVIO6+RkazI4y4dVeeP3KMP8nxfhzIbzTMNSkyynps/deZFjpDWqRhG+Dg==", "requires": { - "@nteract/messaging": "^7.0.10", - "@nteract/outputs": "^3.0.9", - "codemirror": "5.57.0", + "@nteract/messaging": "^7.0.19", + "@nteract/outputs": "^3.0.11", + "codemirror": "5.61.1", "rxjs": "^6.3.3" + }, + "dependencies": { + "@nteract/commutable": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@nteract/commutable/-/commutable-7.4.5.tgz", + "integrity": "sha512-RYqyMvkFt/04GQ9T+hGYgr9/LEy0dAYJ2QKn930TFX004KjfBT6Tt8VSLFyHWkXqPwyJ0jKMCJwqLcGOI/atqg==", + "requires": { + "immutable": "^4.0.0-rc.12", + "uuid": "^8.0.0" + } + }, + "@nteract/messaging": { + "version": "7.0.19", + "resolved": "https://registry.npmjs.org/@nteract/messaging/-/messaging-7.0.19.tgz", + "integrity": "sha512-gRPMxJr741/BshrfCcPSbm5iVyRU2TKmAv9jeQzk0MZEGy+Y1A0REO+eptkt4Ma0OXlvDxON6JEDauk8+2xt4w==", + "requires": { + "@nteract/types": "^7.1.9", + "@types/uuid": "^8.0.0", + "lodash.clonedeep": "^4.5.0", + "rxjs": "^6.6.0", + "uuid": "^8.0.0" + } + }, + "@nteract/outputs": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@nteract/outputs/-/outputs-3.0.11.tgz", + "integrity": "sha512-LeT9ViBf+fTPSubZ9dMe7128kg0rl1jIG54V0n2GiU5RuYnUz21FU0IOaLMPUfFMO1VyVEOW5jDc3PAQx5/Kwg==", + "requires": { + "@nteract/markdown": "^4.5.2", + "@nteract/mathjax": "^4.0.11", + "ansi-to-react": "^6.0.5", + "react-json-tree": "^0.12.1" + } + }, + "@nteract/types": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/@nteract/types/-/types-7.1.9.tgz", + "integrity": "sha512-a7lGMWdjfz2QGlZbAiFHifU9Nhk9ntwg/iKUTMIMRPY1Wfs5UreHSMt+vZ8OY5HGjxicfHozBatGDKXeKXFHMQ==", + "requires": { + "@nteract/commutable": "^7.4.5", + "immutable": "^4.0.0-rc.12", + "rxjs": "^6.6.0", + "uuid": "^8.0.0" + } + }, + "react-base16-styling": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.7.0.tgz", + "integrity": "sha512-lTa/VSFdU6BOAj+FryOe7OTZ0OBP8GXPOnCS0QnZi7G3zhssWgIgwl0eUL77onXx/WqKPFndB3ZeC77QC/l4Dw==", + "requires": { + "base16": "^1.0.0", + "lodash.curry": "^4.1.1", + "lodash.flow": "^3.5.0", + "pure-color": "^1.3.0" + } + }, + "react-json-tree": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.12.1.tgz", + "integrity": "sha512-j6fkRY7ha9XMv1HPVakRCsvyFwHGR5AZuwO8naBBeZXnZbbLor5tpcUxS/8XD01+D1v7ZN5p+7LU+9V1uyASiQ==", + "requires": { + "prop-types": "^15.7.2", + "react-base16-styling": "^0.7.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } } }, "@nteract/epics": { @@ -8067,9 +8137,9 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "codemirror": { - "version": "5.57.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.57.0.tgz", - "integrity": "sha512-WGc6UL7Hqt+8a6ZAsj/f1ApQl3NPvHY/UQSzG6fB6l4BjExgVdhFaxd7mRTw1UCiYe/6q86zHP+kfvBQcZGvUg==" + "version": "5.61.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.61.1.tgz", + "integrity": "sha512-+D1NZjAucuzE93vJGbAaXzvoBHwp9nJZWWWF9utjv25+5AZUiah6CIlfb4ikG4MoDsFsCG8niiJH5++OO2LgIQ==" }, "collapse-white-space": { "version": "1.0.6", diff --git a/package.json b/package.json index afaaed826..1e5480359 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "@nteract/data-explorer": "8.0.3", "@nteract/directory-listing": "2.0.6", "@nteract/dropdown-menu": "1.0.1", - "@nteract/editor": "10.1.2", + "@nteract/editor": "10.1.12", "@nteract/fixtures": "2.3.0", "@nteract/iron-icons": "1.0.0", "@nteract/jupyter-widgets": "2.0.0", diff --git a/src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx b/src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx index 805317627..3bbc6a538 100644 --- a/src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx +++ b/src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx @@ -55,7 +55,7 @@ export class NotebookViewerComponent databaseAccountName: undefined, defaultExperience: "NotebookViewer", isReadOnly: true, - cellEditorType: "monaco", + cellEditorType: "codemirror", autoSaveInterval: 365 * 24 * 3600 * 1000, // There is no way to turn off auto-save, set to 1 year contentProvider: contents.JupyterContentProvider, // NotebookViewer only knows how to talk to Jupyter contents API }); diff --git a/src/Explorer/Notebook/NotebookClientV2.ts b/src/Explorer/Notebook/NotebookClientV2.ts index e7c1fa289..86318a166 100644 --- a/src/Explorer/Notebook/NotebookClientV2.ts +++ b/src/Explorer/Notebook/NotebookClientV2.ts @@ -21,7 +21,7 @@ import { makeStateRecord, makeTransformsRecord, } from "@nteract/core"; -import { configOption, createConfigCollection, defineConfigOption } from "@nteract/mythic-configuration"; +import { configOption, defineConfigOption } from "@nteract/mythic-configuration"; import { Media } from "@nteract/outputs"; import TransformVDOM from "@nteract/transform-vdom"; import * as Immutable from "immutable"; @@ -242,22 +242,27 @@ export class NotebookClientV2 { ); // Additional configuration - this.store.dispatch(configOption("editorType").action(params.cellEditorType ?? "monaco")); + this.store.dispatch(configOption("editorType").action(params.cellEditorType ?? "codemirror")); this.store.dispatch( configOption("autoSaveInterval").action(params.autoSaveInterval ?? Constants.Notebook.autoSaveIntervalMs) ); - createConfigCollection({ - key: "monaco", - }); - defineConfigOption({ - label: "Show Line numbers", - key: "monaco.lineNumbers", - values: [ - { label: "Yes", value: true }, - { label: "No", value: false }, - ], - defaultValue: true, - }); + this.store.dispatch(configOption("codeMirror.lineNumbers").action(true)); + + const readOnlyConfigOption = configOption("codeMirror.readOnly"); + const readOnlyValue = params.isReadOnly ? "nocursor" : undefined; + if (!readOnlyConfigOption) { + defineConfigOption({ + label: "Read-only", + key: "codeMirror.readOnly", + values: [ + { label: "Read-Only", value: "nocursor" }, + { label: "Not read-only", value: undefined }, + ], + defaultValue: readOnlyValue, + }); + } else { + this.store.dispatch(readOnlyConfigOption.action(readOnlyValue)); + } } /** diff --git a/src/Explorer/Notebook/NotebookComponent/NotebookComponent.less b/src/Explorer/Notebook/NotebookComponent/NotebookComponent.less index 36a819b88..1bd303e1d 100644 --- a/src/Explorer/Notebook/NotebookComponent/NotebookComponent.less +++ b/src/Explorer/Notebook/NotebookComponent/NotebookComponent.less @@ -1,10 +1,10 @@ .notebookComponentContainer { - text-transform:none; - line-height:1.28581; - letter-spacing:0; - font-size:14px; - font-weight:400; - color:#182026; + text-transform: none; + line-height: 1.28581; + letter-spacing: 0; + font-size: 14px; + font-weight: 400; + color: #182026; height: 100%; .hotKeys { diff --git a/src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.less b/src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.less index 541062c6f..d124cd0f2 100644 --- a/src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.less +++ b/src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.less @@ -1,56 +1,68 @@ .NotebookReadOnlyRender { - .nteract-cell-container { - margin-bottom: 10px; - } + .nteract-cell-container { + margin-bottom: 10px; + } - .nteract-cell { - padding: 0.5px; - border: 1px solid #ffffff; - border-left: 3px solid #ffffff; - } + .nteract-cell { + padding: 0.5px; + border: 1px solid #ffffff; + border-left: 3px solid #ffffff; + } - .CodeMirror-scroll { - background-color: #f5f5f5; - } + .CodeMirror-scroll { + overflow: hidden !important; + } - .CodeMirror-lines { - cursor: default; - } + .CodeMirror-lines { + cursor: default; + } - .nteract-cell:hover { - border: 1px solid #0078d4; - border-left: 3px solid #0078d4; + .CodeMirror { + height: inherit; + } - .CodeMirror-scroll { - background-color: #ffffff; - } + .CodeMirror-scroll, + .CodeMirror-linenumber, + .CodeMirror-gutters { + background-color: #f5f5f5; + } - .nteract-cell-outputs { - border-top: 1px solid #d7d7d7; - } + .nteract-cell:hover { + border: 1px solid #0078d4; + border-left: 3px solid #0078d4; - .nteract-md-cell { - background-color: #ffffff; - } + .CodeMirror-scroll, + .CodeMirror-linenumber, + .CodeMirror-gutters { + background-color: #ffffff; } .nteract-cell-outputs { - padding: 10px; - border-top: 1px solid #ffffff; - - pre { - background-color: #ffffff; - border: none; - padding: 0px; - margin: 0px; - } + border-top: 1px solid #d7d7d7; } .nteract-md-cell { - background-color: #f5f5f5; + background-color: #ffffff; } + } - .nteract-cell:hover.nteract-md-cell { - background-color: #ffffff; + .nteract-cell-outputs { + padding: 10px; + border-top: 1px solid #ffffff; + + pre { + background-color: #ffffff; + border: none; + padding: 0px; + margin: 0px; } + } + + .nteract-md-cell { + background-color: #f5f5f5; + } + + .nteract-cell:hover.nteract-md-cell { + background-color: #ffffff; + } } diff --git a/src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx b/src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx index 7fcdd2579..f912acd4a 100644 --- a/src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx +++ b/src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx @@ -1,6 +1,6 @@ import { actions, ContentRef } from "@nteract/core"; import { Cells, CodeCell, RawCell } from "@nteract/stateful-components"; -import MonacoEditor from "@nteract/stateful-components/lib/inputs/connected-editors/monacoEditor"; +import CodeMirrorEditor from "@nteract/stateful-components/lib/inputs/connected-editors/codemirror"; import { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor"; import Prompt, { PassedPromptProps } from "@nteract/stateful-components/lib/inputs/prompt"; import * as React from "react"; @@ -67,8 +67,8 @@ class NotebookReadOnlyRenderer extends React.Component { ? () => : undefined, editor: { - monaco: (props: PassedEditorProps) => - this.props.hideInputs ? <> : , + codemirror: (props: PassedEditorProps) => + this.props.hideInputs ? <> : , }, }} @@ -84,8 +84,8 @@ class NotebookReadOnlyRenderer extends React.Component { {{ editor: { - monaco: (props: PassedEditorProps) => - this.props.hideInputs ? <> : , + codemirror: (props: PassedEditorProps) => + this.props.hideInputs ? <> : , }, }} diff --git a/src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.less b/src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.less index c680f8f56..ed77b9fb7 100644 --- a/src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.less +++ b/src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.less @@ -3,110 +3,122 @@ @HighlightColor: #0078d4; .NotebookRendererContainer { - display: flex; - flex-direction: column; - height: 100%; - overflow: hidden; + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; } .NotebookRenderer { - overflow: auto; - flex-grow: 1; + overflow: auto; + flex-grow: 1; - .nteract-cells { - padding-top: 0px; + .nteract-cells { + padding-top: 0px; + } + + .nteract-cell-container { + margin-bottom: 10px; + + .nteract-cell { + padding: 0.5px; + border: 1px solid #ffffff; + border-left: 3px solid #ffffff; + + .CellContextMenuButton { + position: sticky; + z-index: 1; + top: 0px; + right: 0px; + margin: 0px 0px 0px -100%; + float: right; + visibility: hidden; + } } - .nteract-cell-container { - margin-bottom: 10px; - - .nteract-cell { - padding: 0.5px; - border: 1px solid #ffffff; - border-left: 3px solid #ffffff; - - .CellContextMenuButton { - position: sticky; - z-index: 1; - top: 0px; - right: 0px; - margin: 0px 0px 0px -100%; - float: right; - visibility: hidden; - } - } - - .CodeMirror-scroll, .CodeMirror-linenumber, .CodeMirror-gutters { - background-color: #f5f5f5; - } - - .nteract-cell:hover { - border: 1px solid @HoverColor; - border-left: 3px solid @HoverColor; - - .CellContextMenuButton { - visibility: visible; - } - } + .CodeMirror-scroll { + overflow: hidden !important; } - .nteract-cell-container.selected { - .nteract-cell { - border: 1px solid @HighlightColor; - border-left: 3px solid @HighlightColor; - } + .CodeMirror-scroll, + .CodeMirror-linenumber, + .CodeMirror-gutters { + background-color: #f5f5f5; } - // White background when hovered or selected - .nteract-cell:hover, .nteract-cell-container.selected .nteract-cell { - .CodeMirror-scroll, .CodeMirror-linenumber, .CodeMirror-gutters { - background-color: #ffffff; - } + .CodeMirror { + height: inherit; + } - .CodeMirror-linenumber { - color: #015CDA; - } + .nteract-cell:hover { + border: 1px solid @HoverColor; + border-left: 3px solid @HoverColor; - .nteract-cell-outputs { - border-top: 1px solid @HoverColor; - } + .CellContextMenuButton { + visibility: visible; + } + } + } - .nteract-md-cell { - background-color: #ffffff; - } + .nteract-cell-container.selected { + .nteract-cell { + border: 1px solid @HighlightColor; + border-left: 3px solid @HighlightColor; + } + } + + // White background when hovered or selected + .nteract-cell:hover, + .nteract-cell-container.selected .nteract-cell { + .CodeMirror-scroll, + .CodeMirror-linenumber, + .CodeMirror-gutters { + background-color: #ffffff; + } + + .CodeMirror-linenumber { + color: #015cda; } .nteract-cell-outputs { - padding: 10px; - border-top: 1px solid #ffffff; - - pre { - background-color: #ffffff; - border: none; - padding: 0px; - margin: 0px; - } + border-top: 1px solid @HoverColor; } .nteract-md-cell { - background-color: #f5f5f5; + background-color: #ffffff; } + } - .nteract-cell:hover.nteract-md-cell { - background-color: #ffffff; - } + .nteract-cell-outputs { + padding: 10px; + border-top: 1px solid #ffffff; - .nteract-md-cell .ntreact-cell-source { - width: 100%; + pre { + background-color: #ffffff; + border: none; + padding: 0px; + margin: 0px; } + } + + .nteract-md-cell { + background-color: #f5f5f5; + } + + .nteract-cell:hover.nteract-md-cell { + background-color: #ffffff; + } + + .nteract-md-cell .ntreact-cell-source { + width: 100%; + } } - // Undo tree.less .expanded::before { - content: ''; + content: ""; } .monaco-editor .monaco-list .main { - background-color: transparent; -} \ No newline at end of file + background-color: transparent; +} diff --git a/src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx b/src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx index db3f8d5ad..792cd5e0a 100644 --- a/src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx +++ b/src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx @@ -2,7 +2,7 @@ import { CellId } from "@nteract/commutable"; import { CellType } from "@nteract/commutable/src"; import { actions, ContentRef, selectors } from "@nteract/core"; import { Cells, CodeCell, RawCell } from "@nteract/stateful-components"; -import MonacoEditor from "@nteract/stateful-components/lib/inputs/connected-editors/monacoEditor"; +import CodeMirrorEditor from "@nteract/stateful-components/lib/inputs/connected-editors/codemirror"; import { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor"; import * as React from "react"; import { DndProvider } from "react-dnd"; @@ -120,7 +120,9 @@ class BaseNotebookRenderer extends React.Component { {{ editor: { - monaco: (props: PassedEditorProps) => , + codemirror: (props: PassedEditorProps) => ( + + ), }, prompt: ({ id, contentRef }: { id: CellId; contentRef: ContentRef }) => ( @@ -142,7 +144,9 @@ class BaseNotebookRenderer extends React.Component { {{ editor: { - monaco: (props: PassedEditorProps) => , + codemirror: (props: PassedEditorProps) => ( + + ), }, toolbar: () => , }} @@ -157,7 +161,9 @@ class BaseNotebookRenderer extends React.Component { {{ editor: { - monaco: (props: PassedEditorProps) => , + codemirror: (props: PassedEditorProps) => ( + + ), }, toolbar: () => , }} diff --git a/src/Explorer/Notebook/notebookClientV2.test.ts b/src/Explorer/Notebook/notebookClientV2.test.ts index bb0b6bef7..4313932b5 100644 --- a/src/Explorer/Notebook/notebookClientV2.test.ts +++ b/src/Explorer/Notebook/notebookClientV2.test.ts @@ -1,8 +1,8 @@ jest.mock("./NotebookComponent/store"); jest.mock("@nteract/core"); +import { defineConfigOption } from "@nteract/mythic-configuration"; import { NotebookClientV2 } from "./NotebookClientV2"; import configureStore from "./NotebookComponent/store"; -import { defineConfigOption } from "@nteract/mythic-configuration"; describe("auto start kernel", () => { it("configure autoStartKernelOnNotebookOpen properly depending whether notebook is/is not read-only", async () => { @@ -24,6 +24,12 @@ describe("auto start kernel", () => { defaultValue: 1234, }); + defineConfigOption({ + label: "Line numbers", + key: "codeMirror.lineNumbers", + defaultValue: true, + }); + [true, false].forEach((isReadOnly) => { new NotebookClientV2({ connectionInfo: {