1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

more fixes/refactoring + get rid of "react-monaco-editor"

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2021-10-01 15:42:50 +03:00
parent 65aadbac52
commit 9da10dc7b0
7 changed files with 135 additions and 103 deletions

View File

@ -433,7 +433,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
await frame.waitForTimeout(100_000);
}
const inputField = await frame.waitForSelector(".CreateResource div.react-monaco-editor-container");
const inputField = await frame.waitForSelector(".CreateResource .MonacoEditor");
await inputField.click();
await inputField.type("apiVersion: v1", { delay: 10 });

View File

@ -232,7 +232,6 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-material-ui-carousel": "^2.3.1",
"react-monaco-editor": "^0.44.0",
"react-router": "^5.2.0",
"react-virtualized-auto-sizer": "^1.0.6",
"readable-stream": "^3.6.0",

View File

@ -122,6 +122,7 @@ export class AddCluster extends React.Component {
</p>
<div className="flex column">
<MonacoEditor
autoFocus={true}
value={this.customConfig}
onChange={(value: string) => {
this.customConfig = value;

View File

@ -20,7 +20,7 @@
*/
.MonacoEditor {
width: inherit;
height: inherit;
width: 100%;
height: 100%;
flex: 1;
}

View File

@ -21,27 +21,45 @@
import "./monaco-editor.scss";
import React from "react";
import { computed, makeObservable, observable, reaction, toJS, when } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import * as monaco from "monaco-editor";
import { action, computed, makeObservable, observable, reaction, toJS, when } from "mobx";
import { observer } from "mobx-react";
import { editor, Uri } from "monaco-editor";
import logger from "../../../common/logger";
import ReactMonacoEditor, { EditorDidMount, MonacoEditorProps } from "react-monaco-editor";
import { ThemeStore } from "../../theme.store";
import { UserStore } from "../../../common/user-store";
import { cssNames } from "../../utils";
import { cssNames, disposer } from "../../utils";
interface Props extends MonacoEditorProps {
id?: string; // associate editor's model.uri with some ID (e.g. DockStore.TabId)
export interface MonacoEditorProps {
id?: string; // associating editor's ID with created model.uri
value?: string; // initial text value for editor
className?: string;
autoFocus?: boolean;
readOnly?: boolean;
theme?: "vs" /* default, light theme */ | "vs-dark" | "hc-black" | string;
language?: "yaml" | "json"; // configure bundled list of languages in via MonacoWebpackPlugin({languages: []})
onError?(error: string): void; // TODO: validation or some another occurred error
options?: editor.IStandaloneEditorConstructionOptions; // customize editor's initialization options
onChange?: onChangeCallback;
onError?: onErrorCallback;
onDidLayoutChange?(info: editor.EditorLayoutInfo): void;
onDidContentSizeChange?(evt: editor.IContentSizeChangedEvent): void;
}
export const defaultEditorProps: Partial<Props> = {
export interface onChangeCallback {
(value: string, data: {
model: editor.ITextModel, // current model
event: editor.IModelContentChangedEvent;
}): void;
}
export interface onErrorCallback {
(error: string): void; // TODO: provide validation or some another occurred error
}
export const defaultEditorProps: Partial<MonacoEditorProps> = {
value: "",
options: {},
language: "yaml",
autoFocus: false,
get theme(): string {
// theme for monaco-editor defined in `src/renderer/themes/lens-*.json`
return ThemeStore.getInstance().activeTheme.monacoTheme;
@ -49,28 +67,32 @@ export const defaultEditorProps: Partial<Props> = {
};
@observer
export class MonacoEditor extends React.Component<Props> {
export class MonacoEditor extends React.Component<MonacoEditorProps> {
static defaultProps = defaultEditorProps as object;
static models = new WeakMap<MonacoEditor, monaco.editor.ITextModel[]>();
static viewStates = new WeakMap<monaco.editor.ITextModel, monaco.editor.ICodeEditorViewState>();
static models = new WeakMap<MonacoEditor, editor.ITextModel[]>();
static viewStates = new WeakMap<editor.ITextModel, editor.ICodeEditorViewState>();
@observable.ref editor: monaco.editor.IStandaloneCodeEditor;
public staticId = `editor-id#${Math.round(1e7 * Math.random())}`;
public disposeOnUnmount = disposer();
constructor(props: Props) {
@observable.ref containerElem: HTMLElement;
@observable.ref editor: editor.IStandaloneCodeEditor;
@observable dimensions: { width?: number, height?: number } = {};
@observable unmounting = false;
constructor(props: MonacoEditorProps) {
super(props);
makeObservable(this);
MonacoEditor.models.set(this, []);
disposeOnUnmount(this, [
reaction(() => this.model, this.onModelChange),
]);
this.whenReady.then(() => this.bindResizeObserver());
}
get whenReady() {
return when(() => Boolean(this.editor));
get whenEditorReady() {
return when(() => Boolean(this.containerElem && this.editor));
}
get whenUnmounting() {
return when(() => this.unmounting);
}
/**
@ -82,8 +104,8 @@ export class MonacoEditor extends React.Component<Props> {
for (const entry of entries) {
const { width, height } = entry.contentRect;
this.editor.layout({ width, height });
logger.info(`[MONACO]: refreshing dimensions to width=${width} and height=${height}`, entry);
this.setDimensions(width, height);
}
});
@ -94,16 +116,16 @@ export class MonacoEditor extends React.Component<Props> {
return () => resizeObserver.unobserve(containerElem);
}
onModelChange = (model: monaco.editor.ITextModel, oldModel?: monaco.editor.ITextModel) => {
onModelChange = (model: editor.ITextModel, oldModel?: editor.ITextModel) => {
logger.info("[MONACO]: model change", { model, oldModel });
this.saveViewState(oldModel); // save previously used view-model state
this.editor.setModel(model);
this.editor.restoreViewState(this.getViewState(model));
this.editor.restoreViewState(this.getViewState(model)); // restore cursor position, selection, etc.
this.editor.layout();
this.editor.focus();
};
@computed get model(): monaco.editor.ITextModel {
@computed get model(): editor.ITextModel {
const { language, value, id = this.staticId } = this.props;
const model = this.getModelById(id);
@ -112,34 +134,94 @@ export class MonacoEditor extends React.Component<Props> {
// creating new temporary model
const uri = this.createUri(id);
const newModel = monaco.editor.createModel(value, language, uri);
const newModel = editor.createModel(value, language, uri);
MonacoEditor.models.get(this).push(newModel);
logger.info(`[MONACO]: creating new model ${uri}`, newModel);
MonacoEditor.models.get(this).push(newModel);
return newModel;
}
editorDidMount: EditorDidMount = (editor, monaco) => {
this.props.editorDidMount?.(editor, monaco);
this.editor = editor;
@computed get globalEditorOptions() {
return toJS(UserStore.getInstance().editorConfiguration);
}
componentDidMount() {
this.createEditor();
logger.info(`[MONACO]: editor did mounted`);
if (this.props.autoFocus) {
this.editor.focus();
}
};
}
componentWillUnmount() {
logger.info(`[MONACO]: unmounting editor..`);
this.unmounting = true;
this.disposeOnUnmount();
MonacoEditor.models.get(this).forEach(model => model.dispose());
MonacoEditor.models.delete(this);
this.editor?.dispose();
}
createUri(id: string): monaco.Uri {
return monaco.Uri.file(`/monaco-editor/${id}`);
private createEditor = (): void => {
if (!this.containerElem || this.editor || this.unmounting) {
return;
}
const { language, theme, readOnly, value: defaultValue, options } = this.props;
this.editor = editor.create(this.containerElem, {
model: this.model,
value: defaultValue,
language,
theme,
readOnly,
...this.globalEditorOptions,
...options,
});
logger.info(`[MONACO]: editor created for language=${language}, theme=${theme}`);
const onDidLayoutChangeDisposer = this.editor.onDidLayoutChange(layoutInfo => {
this.props.onDidLayoutChange?.(layoutInfo);
// logger.info("[MONACO]: onDidLayoutChange()", layoutInfo);
});
const onValueChangeDisposer = this.editor.onDidChangeModelContent(event => {
const value = this.editor.getValue();
// logger.info("[MONACO]: value changed", { value, event });
this.props.onChange?.(value, {
model: this.model,
event,
});
});
const onContentSizeChangeDisposer = this.editor.onDidContentSizeChange((params) => {
this.props.onDidContentSizeChange?.(params);
// logger.info("[MONACO]: onDidContentSizeChange():", params)
});
this.disposeOnUnmount.push(
reaction(() => this.model, this.onModelChange),
() => onDidLayoutChangeDisposer.dispose(),
() => onValueChangeDisposer.dispose(),
() => onContentSizeChangeDisposer.dispose(),
this.bindResizeObserver(),
);
};
@action
setDimensions(width: number, height: number) {
this.dimensions.width = width;
this.dimensions.height = height;
this.editor?.layout({ width, height });
}
getViewState(model = this.model): monaco.editor.ICodeEditorViewState {
createUri(id: string): Uri {
return Uri.file(`/monaco-editor/${id}`);
}
getViewState(model = this.model): editor.ICodeEditorViewState {
return MonacoEditor.viewStates.get(model) ?? null;
}
@ -148,7 +230,7 @@ export class MonacoEditor extends React.Component<Props> {
MonacoEditor.viewStates.set(model, this.editor.saveViewState());
}
getModelById(id: string): monaco.editor.ITextModel | null {
getModelById(id: string): editor.ITextModel | null {
const uri = this.createUri(id);
for (const model of MonacoEditor.models.get(this)) {
@ -166,23 +248,16 @@ export class MonacoEditor extends React.Component<Props> {
return this.editor.getValue(opts);
}
bindRef = (elem: HTMLElement) => this.containerElem = elem;
render() {
const { autoFocus, readOnly, className, options = {}, ...reactMonacoEditorProps } = this.props;
const globalOptions = toJS(UserStore.getInstance().editorConfiguration);
const { className } = this.props;
return (
<React.Fragment>
<ReactMonacoEditor
{...reactMonacoEditorProps}
className={cssNames("MonacoEditor", className)}
editorDidMount={this.editorDidMount}
options={{
model: this.model,
readOnly,
...globalOptions,
...options,
}}/>
</React.Fragment>
<div
className={cssNames("MonacoEditor", className)}
ref={this.bindRef}
/>
);
}
}

View File

@ -150,8 +150,10 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura
new ProgressBarPlugin(),
new ForkTsCheckerPlugin(),
// see also: https://github.com/Microsoft/monaco-editor-webpack-plugin#options
new MonacoWebpackPlugin({
// available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options
// publicPath: "/",
// filename: "[name].worker.js",
languages: ["json", "yaml"],
globalAPI: isDevelopment,
}),

View File

@ -4683,7 +4683,7 @@ debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6:
dependencies:
ms "^2.1.1"
debuglog@*, debuglog@^1.0.1:
debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
@ -7392,7 +7392,7 @@ import-local@^3.0.2:
pkg-dir "^4.2.0"
resolve-cwd "^3.0.0"
imurmurhash@*, imurmurhash@^0.1.4:
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
@ -9160,11 +9160,6 @@ lodash-es@^4.17.20:
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash._baseindexof@*:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
@ -9173,33 +9168,11 @@ lodash._baseuniq@~4.6.0:
lodash._createset "~4.0.0"
lodash._root "~3.0.0"
lodash._bindcallback@*:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
lodash._cacheindexof@*:
version "3.0.2"
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
lodash._createcache@*:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
dependencies:
lodash._getnative "^3.0.0"
lodash._createset@~4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
lodash._getnative@*, lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
lodash._root@~3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
@ -9225,11 +9198,6 @@ lodash.isequal@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.restparam@*:
version "3.6.1"
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
lodash.toarray@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
@ -9775,11 +9743,6 @@ monaco-editor-webpack-plugin@^4.2.0:
dependencies:
loader-utils "^2.0.0"
monaco-editor@^0.26.1:
version "0.26.1"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.26.1.tgz#62bb5f658bc95379f8abb64b147632bd1c019d73"
integrity sha512-mm45nUrBDk0DgZKgbD7+bhDOtcAFNGPJJRAdS6Su1kTGl6XEgC7U3xOmDUW/0RrLf+jlvCGaqLvD4p2VjwuwwQ==
monaco-editor@^0.28.1:
version "0.28.1"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.28.1.tgz#732788ff2172d59e6d436b206da8cac715413940"
@ -11747,14 +11710,6 @@ react-material-ui-carousel@^2.3.1:
auto-bind "^2.1.1"
react-swipeable "^6.1.0"
react-monaco-editor@^0.44.0:
version "0.44.0"
resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.44.0.tgz#9f966fd00b6c30e8be8873a3fbc86f14a0da2ba4"
integrity sha512-GPheXTIpBXpwv857H7/jA8HX5yae4TJ7vFwDJ5iTvy05LxIQTsD3oofXznXGi66lVA93ST/G7wRptEf4CJ9dOg==
dependencies:
monaco-editor "^0.26.1"
prop-types "^15.7.2"
react-redux@^7.2.0:
version "7.2.3"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.3.tgz#4c084618600bb199012687da9e42123cca3f0be9"