Switch notebook editor from Monaco back to Code Mirror (#901)

This commit is contained in:
Laurent Nguyen 2021-06-23 21:05:52 +02:00 committed by GitHub
parent 738a02a0f3
commit 6b35ab03f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 267 additions and 156 deletions

88
package-lock.json generated
View File

@ -3709,14 +3709,84 @@
} }
}, },
"@nteract/editor": { "@nteract/editor": {
"version": "10.1.2", "version": "10.1.12",
"resolved": "https://registry.npmjs.org/@nteract/editor/-/editor-10.1.2.tgz", "resolved": "https://registry.npmjs.org/@nteract/editor/-/editor-10.1.12.tgz",
"integrity": "sha512-Wtj0kJUSoBZsWUh82JGt6miqYS0jt0k+3SD3cnW9socayxp2KB0Qbqhh2NtrF9ysxVHWnQT8iUarJjpGIdNyng==", "integrity": "sha512-bsUrCctukjWdpKNWQOQmhfxMCQ/SBVIO6+RkazI4y4dVeeP3KMP8nxfhzIbzTMNSkyynps/deZFjpDWqRhG+Dg==",
"requires": { "requires": {
"@nteract/messaging": "^7.0.10", "@nteract/messaging": "^7.0.19",
"@nteract/outputs": "^3.0.9", "@nteract/outputs": "^3.0.11",
"codemirror": "5.57.0", "codemirror": "5.61.1",
"rxjs": "^6.3.3" "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": { "@nteract/epics": {
@ -8067,9 +8137,9 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
}, },
"codemirror": { "codemirror": {
"version": "5.57.0", "version": "5.61.1",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.57.0.tgz", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.61.1.tgz",
"integrity": "sha512-WGc6UL7Hqt+8a6ZAsj/f1ApQl3NPvHY/UQSzG6fB6l4BjExgVdhFaxd7mRTw1UCiYe/6q86zHP+kfvBQcZGvUg==" "integrity": "sha512-+D1NZjAucuzE93vJGbAaXzvoBHwp9nJZWWWF9utjv25+5AZUiah6CIlfb4ikG4MoDsFsCG8niiJH5++OO2LgIQ=="
}, },
"collapse-white-space": { "collapse-white-space": {
"version": "1.0.6", "version": "1.0.6",

View File

@ -22,7 +22,7 @@
"@nteract/data-explorer": "8.0.3", "@nteract/data-explorer": "8.0.3",
"@nteract/directory-listing": "2.0.6", "@nteract/directory-listing": "2.0.6",
"@nteract/dropdown-menu": "1.0.1", "@nteract/dropdown-menu": "1.0.1",
"@nteract/editor": "10.1.2", "@nteract/editor": "10.1.12",
"@nteract/fixtures": "2.3.0", "@nteract/fixtures": "2.3.0",
"@nteract/iron-icons": "1.0.0", "@nteract/iron-icons": "1.0.0",
"@nteract/jupyter-widgets": "2.0.0", "@nteract/jupyter-widgets": "2.0.0",

View File

@ -55,7 +55,7 @@ export class NotebookViewerComponent
databaseAccountName: undefined, databaseAccountName: undefined,
defaultExperience: "NotebookViewer", defaultExperience: "NotebookViewer",
isReadOnly: true, isReadOnly: true,
cellEditorType: "monaco", cellEditorType: "codemirror",
autoSaveInterval: 365 * 24 * 3600 * 1000, // There is no way to turn off auto-save, set to 1 year 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 contentProvider: contents.JupyterContentProvider, // NotebookViewer only knows how to talk to Jupyter contents API
}); });

View File

@ -21,7 +21,7 @@ import {
makeStateRecord, makeStateRecord,
makeTransformsRecord, makeTransformsRecord,
} from "@nteract/core"; } from "@nteract/core";
import { configOption, createConfigCollection, defineConfigOption } from "@nteract/mythic-configuration"; import { configOption, defineConfigOption } from "@nteract/mythic-configuration";
import { Media } from "@nteract/outputs"; import { Media } from "@nteract/outputs";
import TransformVDOM from "@nteract/transform-vdom"; import TransformVDOM from "@nteract/transform-vdom";
import * as Immutable from "immutable"; import * as Immutable from "immutable";
@ -242,22 +242,27 @@ export class NotebookClientV2 {
); );
// Additional configuration // Additional configuration
this.store.dispatch(configOption("editorType").action(params.cellEditorType ?? "monaco")); this.store.dispatch(configOption("editorType").action(params.cellEditorType ?? "codemirror"));
this.store.dispatch( this.store.dispatch(
configOption("autoSaveInterval").action(params.autoSaveInterval ?? Constants.Notebook.autoSaveIntervalMs) configOption("autoSaveInterval").action(params.autoSaveInterval ?? Constants.Notebook.autoSaveIntervalMs)
); );
createConfigCollection({ this.store.dispatch(configOption("codeMirror.lineNumbers").action(true));
key: "monaco",
}); const readOnlyConfigOption = configOption("codeMirror.readOnly");
defineConfigOption({ const readOnlyValue = params.isReadOnly ? "nocursor" : undefined;
label: "Show Line numbers", if (!readOnlyConfigOption) {
key: "monaco.lineNumbers", defineConfigOption({
values: [ label: "Read-only",
{ label: "Yes", value: true }, key: "codeMirror.readOnly",
{ label: "No", value: false }, values: [
], { label: "Read-Only", value: "nocursor" },
defaultValue: true, { label: "Not read-only", value: undefined },
}); ],
defaultValue: readOnlyValue,
});
} else {
this.store.dispatch(readOnlyConfigOption.action(readOnlyValue));
}
} }
/** /**

View File

@ -1,10 +1,10 @@
.notebookComponentContainer { .notebookComponentContainer {
text-transform:none; text-transform: none;
line-height:1.28581; line-height: 1.28581;
letter-spacing:0; letter-spacing: 0;
font-size:14px; font-size: 14px;
font-weight:400; font-weight: 400;
color:#182026; color: #182026;
height: 100%; height: 100%;
.hotKeys { .hotKeys {

View File

@ -1,56 +1,68 @@
.NotebookReadOnlyRender { .NotebookReadOnlyRender {
.nteract-cell-container { .nteract-cell-container {
margin-bottom: 10px; margin-bottom: 10px;
} }
.nteract-cell { .nteract-cell {
padding: 0.5px; padding: 0.5px;
border: 1px solid #ffffff; border: 1px solid #ffffff;
border-left: 3px solid #ffffff; border-left: 3px solid #ffffff;
} }
.CodeMirror-scroll { .CodeMirror-scroll {
background-color: #f5f5f5; overflow: hidden !important;
} }
.CodeMirror-lines { .CodeMirror-lines {
cursor: default; cursor: default;
} }
.nteract-cell:hover { .CodeMirror {
border: 1px solid #0078d4; height: inherit;
border-left: 3px solid #0078d4; }
.CodeMirror-scroll { .CodeMirror-scroll,
background-color: #ffffff; .CodeMirror-linenumber,
} .CodeMirror-gutters {
background-color: #f5f5f5;
}
.nteract-cell-outputs { .nteract-cell:hover {
border-top: 1px solid #d7d7d7; border: 1px solid #0078d4;
} border-left: 3px solid #0078d4;
.nteract-md-cell { .CodeMirror-scroll,
background-color: #ffffff; .CodeMirror-linenumber,
} .CodeMirror-gutters {
background-color: #ffffff;
} }
.nteract-cell-outputs { .nteract-cell-outputs {
padding: 10px; border-top: 1px solid #d7d7d7;
border-top: 1px solid #ffffff;
pre {
background-color: #ffffff;
border: none;
padding: 0px;
margin: 0px;
}
} }
.nteract-md-cell { .nteract-md-cell {
background-color: #f5f5f5; background-color: #ffffff;
} }
}
.nteract-cell:hover.nteract-md-cell { .nteract-cell-outputs {
background-color: #ffffff; 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;
}
} }

View File

@ -1,6 +1,6 @@
import { actions, ContentRef } from "@nteract/core"; import { actions, ContentRef } from "@nteract/core";
import { Cells, CodeCell, RawCell } from "@nteract/stateful-components"; 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 { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
import Prompt, { PassedPromptProps } from "@nteract/stateful-components/lib/inputs/prompt"; import Prompt, { PassedPromptProps } from "@nteract/stateful-components/lib/inputs/prompt";
import * as React from "react"; import * as React from "react";
@ -67,8 +67,8 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
? () => <SandboxOutputs id={id} contentRef={contentRef} /> ? () => <SandboxOutputs id={id} contentRef={contentRef} />
: undefined, : undefined,
editor: { editor: {
monaco: (props: PassedEditorProps) => codemirror: (props: PassedEditorProps) =>
this.props.hideInputs ? <></> : <MonacoEditor readOnly={true} {...props} editorType={"monaco"} />, this.props.hideInputs ? <></> : <CodeMirrorEditor {...props} editorType="codemirror" />,
}, },
}} }}
</CodeCell> </CodeCell>
@ -84,8 +84,8 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
<RawCell id={id} contentRef={contentRef} cell_type="raw"> <RawCell id={id} contentRef={contentRef} cell_type="raw">
{{ {{
editor: { editor: {
monaco: (props: PassedEditorProps) => codemirror: (props: PassedEditorProps) =>
this.props.hideInputs ? <></> : <MonacoEditor {...props} readOnly={true} editorType={"monaco"} />, this.props.hideInputs ? <></> : <CodeMirrorEditor {...props} editorType="codemirror" />,
}, },
}} }}
</RawCell> </RawCell>

View File

@ -3,110 +3,122 @@
@HighlightColor: #0078d4; @HighlightColor: #0078d4;
.NotebookRendererContainer { .NotebookRendererContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
} }
.NotebookRenderer { .NotebookRenderer {
overflow: auto; overflow: auto;
flex-grow: 1; flex-grow: 1;
.nteract-cells { .nteract-cells {
padding-top: 0px; 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 { .CodeMirror-scroll {
margin-bottom: 10px; overflow: hidden !important;
.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;
}
}
} }
.nteract-cell-container.selected { .CodeMirror-scroll,
.nteract-cell { .CodeMirror-linenumber,
border: 1px solid @HighlightColor; .CodeMirror-gutters {
border-left: 3px solid @HighlightColor; background-color: #f5f5f5;
}
} }
// White background when hovered or selected .CodeMirror {
.nteract-cell:hover, .nteract-cell-container.selected .nteract-cell { height: inherit;
.CodeMirror-scroll, .CodeMirror-linenumber, .CodeMirror-gutters { }
background-color: #ffffff;
}
.CodeMirror-linenumber { .nteract-cell:hover {
color: #015CDA; border: 1px solid @HoverColor;
} border-left: 3px solid @HoverColor;
.nteract-cell-outputs { .CellContextMenuButton {
border-top: 1px solid @HoverColor; visibility: visible;
} }
}
}
.nteract-md-cell { .nteract-cell-container.selected {
background-color: #ffffff; .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 { .nteract-cell-outputs {
padding: 10px; border-top: 1px solid @HoverColor;
border-top: 1px solid #ffffff;
pre {
background-color: #ffffff;
border: none;
padding: 0px;
margin: 0px;
}
} }
.nteract-md-cell { .nteract-md-cell {
background-color: #f5f5f5; background-color: #ffffff;
} }
}
.nteract-cell:hover.nteract-md-cell { .nteract-cell-outputs {
background-color: #ffffff; padding: 10px;
} border-top: 1px solid #ffffff;
.nteract-md-cell .ntreact-cell-source { pre {
width: 100%; 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 // Undo tree.less
.expanded::before { .expanded::before {
content: ''; content: "";
} }
.monaco-editor .monaco-list .main { .monaco-editor .monaco-list .main {
background-color: transparent; background-color: transparent;
} }

View File

@ -2,7 +2,7 @@ import { CellId } from "@nteract/commutable";
import { CellType } from "@nteract/commutable/src"; import { CellType } from "@nteract/commutable/src";
import { actions, ContentRef, selectors } from "@nteract/core"; import { actions, ContentRef, selectors } from "@nteract/core";
import { Cells, CodeCell, RawCell } from "@nteract/stateful-components"; 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 { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
import * as React from "react"; import * as React from "react";
import { DndProvider } from "react-dnd"; import { DndProvider } from "react-dnd";
@ -120,7 +120,9 @@ class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
<CodeCell id={id} contentRef={contentRef} cell_type="code"> <CodeCell id={id} contentRef={contentRef} cell_type="code">
{{ {{
editor: { editor: {
monaco: (props: PassedEditorProps) => <MonacoEditor {...props} editorType={"monaco"} />, codemirror: (props: PassedEditorProps) => (
<CodeMirrorEditor {...props} editorType="codemirror" />
),
}, },
prompt: ({ id, contentRef }: { id: CellId; contentRef: ContentRef }) => ( prompt: ({ id, contentRef }: { id: CellId; contentRef: ContentRef }) => (
<Prompt id={id} contentRef={contentRef} isHovered={false}> <Prompt id={id} contentRef={contentRef} isHovered={false}>
@ -142,7 +144,9 @@ class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
<MarkdownCell id={id} contentRef={contentRef} cell_type="markdown"> <MarkdownCell id={id} contentRef={contentRef} cell_type="markdown">
{{ {{
editor: { editor: {
monaco: (props: PassedEditorProps) => <MonacoEditor {...props} editorType={"monaco"} />, codemirror: (props: PassedEditorProps) => (
<CodeMirrorEditor {...props} editorType="codemirror" />
),
}, },
toolbar: () => <CellToolbar id={id} contentRef={contentRef} />, toolbar: () => <CellToolbar id={id} contentRef={contentRef} />,
}} }}
@ -157,7 +161,9 @@ class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
<RawCell id={id} contentRef={contentRef} cell_type="raw"> <RawCell id={id} contentRef={contentRef} cell_type="raw">
{{ {{
editor: { editor: {
monaco: (props: PassedEditorProps) => <MonacoEditor {...props} editorType={"monaco"} />, codemirror: (props: PassedEditorProps) => (
<CodeMirrorEditor {...props} editorType="codemirror" />
),
}, },
toolbar: () => <CellToolbar id={id} contentRef={contentRef} />, toolbar: () => <CellToolbar id={id} contentRef={contentRef} />,
}} }}

View File

@ -1,8 +1,8 @@
jest.mock("./NotebookComponent/store"); jest.mock("./NotebookComponent/store");
jest.mock("@nteract/core"); jest.mock("@nteract/core");
import { defineConfigOption } from "@nteract/mythic-configuration";
import { NotebookClientV2 } from "./NotebookClientV2"; import { NotebookClientV2 } from "./NotebookClientV2";
import configureStore from "./NotebookComponent/store"; import configureStore from "./NotebookComponent/store";
import { defineConfigOption } from "@nteract/mythic-configuration";
describe("auto start kernel", () => { describe("auto start kernel", () => {
it("configure autoStartKernelOnNotebookOpen properly depending whether notebook is/is not read-only", async () => { it("configure autoStartKernelOnNotebookOpen properly depending whether notebook is/is not read-only", async () => {
@ -24,6 +24,12 @@ describe("auto start kernel", () => {
defaultValue: 1234, defaultValue: 1234,
}); });
defineConfigOption({
label: "Line numbers",
key: "codeMirror.lineNumbers",
defaultValue: true,
});
[true, false].forEach((isReadOnly) => { [true, false].forEach((isReadOnly) => {
new NotebookClientV2({ new NotebookClientV2({
connectionInfo: { connectionInfo: {