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:
parent
65aadbac52
commit
9da10dc7b0
@ -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 });
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
.MonacoEditor {
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}),
|
||||
|
||||
49
yarn.lock
49
yarn.lock
@ -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"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user