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

Expose Lens Monaco Editor component to extensions-api (#5264)

* Expose Lens Monaco Editor component to public, close #5094
This commit is contained in:
Roman 2022-04-25 14:29:49 +03:00 committed by GitHub
parent b7851c577b
commit 11f3cafac3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 33 deletions

View File

@ -178,9 +178,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
} }
const testPodName = "nginx-create-pod-test"; const testPodName = "nginx-create-pod-test";
const monacoEditor = await frame.waitForSelector( const monacoEditor = await frame.waitForSelector(`.Dock.isOpen [data-test-id="monaco-editor"]`);
`.Dock.isOpen [data-test-component="monaco-editor"]`,
);
await monacoEditor.click(); await monacoEditor.click();
await monacoEditor.type("apiVersion: v1", { delay: 10 }); await monacoEditor.type("apiVersion: v1", { delay: 10 });

View File

@ -64,6 +64,11 @@ export * from "../../renderer/components/layout/sub-title";
export * from "../../renderer/components/input/search-input"; export * from "../../renderer/components/input/search-input";
export * from "../../renderer/components/chart/bar-chart"; export * from "../../renderer/components/chart/bar-chart";
export * from "../../renderer/components/chart/pie-chart"; export * from "../../renderer/components/chart/pie-chart";
export {
MonacoEditor,
type MonacoEditorProps, type MonacoEditorId,
type MonacoTheme, type MonacoCustomTheme,
} from "../../renderer/components/monaco-editor";
// kube helpers // kube helpers
export * from "../../renderer/components/kube-detail-params"; export * from "../../renderer/components/kube-detail-params";

View File

@ -9,12 +9,12 @@ import { observer } from "mobx-react";
import { action, computed, makeObservable, observable, reaction } from "mobx"; import { action, computed, makeObservable, observable, reaction } from "mobx";
import { editor, Uri } from "monaco-editor"; import { editor, Uri } from "monaco-editor";
import type { MonacoTheme } from "./monaco-themes"; import type { MonacoTheme } from "./monaco-themes";
import type { MonacoValidator } from "./monaco-validators"; import { type MonacoValidator, monacoValidators } from "./monaco-validators";
import { monacoValidators } from "./monaco-validators";
import { debounce, merge } from "lodash"; import { debounce, merge } from "lodash";
import { cssNames, disposer } from "../../utils"; import { autoBind, cssNames, disposer } from "../../utils";
import { UserStore } from "../../../common/user-store"; import { UserStore } from "../../../common/user-store";
import { ThemeStore } from "../../theme.store"; import { ThemeStore } from "../../theme.store";
import logger from "../../../main/logger";
export type MonacoEditorId = string; export type MonacoEditorId = string;
@ -45,32 +45,28 @@ export const defaultEditorProps: Partial<MonacoEditorProps> = {
@observer @observer
export class MonacoEditor extends React.Component<MonacoEditorProps> { export class MonacoEditor extends React.Component<MonacoEditorProps> {
static defaultProps = defaultEditorProps as object; static readonly defaultProps = defaultEditorProps as object;
static viewStates = new WeakMap<Uri, editor.ICodeEditorViewState>(); static readonly viewStates = new WeakMap<Uri, editor.ICodeEditorViewState>();
static createUri(id: MonacoEditorId): Uri { static createUri(id: MonacoEditorId): Uri {
return Uri.file(`/monaco-editor/${id}`); return Uri.file(`/monaco-editor/${id}`);
} }
public staticId = `editor-id#${Math.round(1e7 * Math.random())}`; private staticId = `editor-id#${Math.round(1e7 * Math.random())}`;
public dispose = disposer(); private dispose = disposer();
// TODO: investigate how to replace with "common/logger"
// currently leads for stucking UI forever & infinite loop.
// e.g. happens on tab change/create, maybe some other cases too.
logger = console;
@observable.ref containerElem: HTMLElement; @observable.ref containerElem: HTMLElement;
@observable.ref editor: editor.IStandaloneCodeEditor; @observable.ref editor: editor.IStandaloneCodeEditor;
@observable dimensions: { width?: number; height?: number } = {}; @observable readonly dimensions: { width?: number; height?: number } = {};
@observable unmounting = false; @observable private unmounting = false;
constructor(props: MonacoEditorProps) { constructor(props: MonacoEditorProps) {
super(props); super(props);
makeObservable(this); makeObservable(this);
autoBind(this);
} }
@computed get id() { @computed get id(): MonacoEditorId {
return this.props.id ?? this.staticId; return this.props.id ?? this.staticId;
} }
@ -94,7 +90,8 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
); );
} }
@computed get logMetadata() { @computed
private get logMetadata() {
return { return {
editorId: this.id, editorId: this.id,
model: this.model, model: this.model,
@ -121,8 +118,8 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
return () => resizeObserver.unobserve(containerElem); return () => resizeObserver.unobserve(containerElem);
} }
onModelChange = (model: editor.ITextModel, oldModel?: editor.ITextModel) => { protected onModelChange(model: editor.ITextModel, oldModel?: editor.ITextModel) {
this.logger?.info("[MONACO]: model change", { model, oldModel }, this.logMetadata); logger.info("[MONACO]: model change", { model, oldModel }, this.logMetadata);
if (oldModel) { if (oldModel) {
this.saveViewState(oldModel); this.saveViewState(oldModel);
@ -134,18 +131,17 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
this.editor.focus(); // keep focus in editor, e.g. when clicking between dock-tabs this.editor.focus(); // keep focus in editor, e.g. when clicking between dock-tabs
this.props.onModelChange?.(model, oldModel); this.props.onModelChange?.(model, oldModel);
this.validateLazy(); this.validateLazy();
}; }
/** /**
* Save current view-model state in the editor. * Save current view-model state in the editor.
* This will allow restore cursor position, selected text, etc. * This will allow restore cursor position, selected text, etc.
* @param {editor.ITextModel} model
*/ */
private saveViewState(model: editor.ITextModel) { protected saveViewState(model: editor.ITextModel) {
MonacoEditor.viewStates.set(model.uri, this.editor.saveViewState()); MonacoEditor.viewStates.set(model.uri, this.editor.saveViewState());
} }
private restoreViewState(model: editor.ITextModel) { protected restoreViewState(model: editor.ITextModel) {
const viewState = MonacoEditor.viewStates.get(model.uri); const viewState = MonacoEditor.viewStates.get(model.uri);
if (viewState) { if (viewState) {
@ -156,9 +152,9 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
componentDidMount() { componentDidMount() {
try { try {
this.createEditor(); this.createEditor();
this.logger?.info(`[MONACO]: editor did mount`, this.logMetadata); logger.info(`[MONACO]: editor did mount`, this.logMetadata);
} catch (error) { } catch (error) {
this.logger?.error(`[MONACO]: mounting failed: ${error}`, this.logMetadata); logger.error(`[MONACO]: mounting failed: ${error}`, this.logMetadata);
} }
} }
@ -168,7 +164,7 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
this.destroy(); this.destroy();
} }
private createEditor() { protected createEditor() {
if (!this.containerElem || this.editor || this.unmounting) { if (!this.containerElem || this.editor || this.unmounting) {
return; return;
} }
@ -184,7 +180,7 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
...this.options, ...this.options,
}); });
this.logger?.info(`[MONACO]: editor created for language=${language}, theme=${theme}`, this.logMetadata); logger.info(`[MONACO]: editor created for language=${language}, theme=${theme}`, this.logMetadata);
this.validateLazy(); // validate initial value this.validateLazy(); // validate initial value
this.restoreViewState(this.model); // restore previous state if any this.restoreViewState(this.model); // restore previous state if any
@ -250,7 +246,8 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
this.editor?.focus(); this.editor?.focus();
} }
validate = action((value = this.getValue()) => { @action
validate(value = this.getValue()) {
const validators: MonacoValidator[] = [ const validators: MonacoValidator[] = [
monacoValidators[this.props.language], // parsing syntax check monacoValidators[this.props.language], // parsing syntax check
].filter(Boolean); ].filter(Boolean);
@ -262,19 +259,21 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
this.props.onError?.(error); // emit error outside this.props.onError?.(error); // emit error outside
} }
} }
}); }
// avoid excessive validations during typing // avoid excessive validations during typing
validateLazy = debounce(this.validate, 250); validateLazy = debounce(this.validate, 250);
bindRef = (elem: HTMLElement) => this.containerElem = elem; protected bindRef(elem: HTMLElement) {
this.containerElem = elem;
}
render() { render() {
const { className, style } = this.props; const { className, style } = this.props;
return ( return (
<div <div
data-test-component="monaco-editor" data-test-id="monaco-editor"
className={cssNames(styles.MonacoEditor, className)} className={cssNames(styles.MonacoEditor, className)}
style={style} style={style}
ref={this.bindRef} ref={this.bindRef}