mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
responding to comments / clean up
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
a33165044e
commit
a02538999a
@ -24,16 +24,14 @@ import glob from "glob";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import { promisify } from "util";
|
||||
import { action, makeObservable, observable } from "mobx";
|
||||
import { action, makeObservable, observable, ObservableMap } from "mobx";
|
||||
import logger from "../../../common/logger";
|
||||
import { DockTabStore } from "./dock-tab.store";
|
||||
import { dockStore, DockTabCreateSpecific, TabKind } from "./dock.store";
|
||||
|
||||
export interface TemplatesGroup {
|
||||
label: string;
|
||||
templates: {
|
||||
[filepath: string]: string; // filepath is relative to templates folder
|
||||
};
|
||||
templates: ObservableMap<string/*filepath*/, string>;
|
||||
}
|
||||
|
||||
export class CreateResourceStore extends DockTabStore<string> {
|
||||
@ -42,16 +40,16 @@ export class CreateResourceStore extends DockTabStore<string> {
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
readonly templateGroups: Record<string, TemplatesGroup> = observable({
|
||||
readonly templateGroups: Record<string, TemplatesGroup> = {
|
||||
[this.appTemplatesFolder]: {
|
||||
label: "Lens Templates",
|
||||
templates: {},
|
||||
templates: observable.map(),
|
||||
},
|
||||
[this.userTemplatesFolder]: {
|
||||
label: "Custom templates",
|
||||
templates: {},
|
||||
templates: observable.map(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
get appTemplatesFolder(): string {
|
||||
// production: declare files to copy in "package.json" -> "build.extraResources"
|
||||
@ -80,9 +78,7 @@ export class CreateResourceStore extends DockTabStore<string> {
|
||||
await fs.ensureDir(sourceFolder);
|
||||
const files = await promisify(glob)("**/*.@(yaml|yml|json)", { cwd: sourceFolder });
|
||||
|
||||
templatesGroup.templates = Object.fromEntries(
|
||||
files.map(filePath => [filePath, "" /* empty: content not loaded yet */])
|
||||
);
|
||||
templatesGroup.templates.replace(files.map(filePath => [filePath, "" /*content*/]));
|
||||
} catch (error) {
|
||||
logger.error(`[CREATE-RESOURCE]: scanning template folders error: ${error}`);
|
||||
}
|
||||
@ -98,9 +94,11 @@ export class CreateResourceStore extends DockTabStore<string> {
|
||||
return ""; // unknown group, exit
|
||||
}
|
||||
|
||||
const template = templatesGroup.templates[filePath];
|
||||
const template = templatesGroup.templates.get(filePath);
|
||||
|
||||
if (template) return template; // return cache, preloaded already
|
||||
if (template) {
|
||||
return template; // return cache, preloaded already
|
||||
}
|
||||
|
||||
try {
|
||||
const templatePath = path.resolve(sourceFolder, filePath);
|
||||
@ -110,7 +108,7 @@ export class CreateResourceStore extends DockTabStore<string> {
|
||||
|
||||
const textContent = await fs.readFile(templatePath, { encoding: "utf-8" });
|
||||
|
||||
templatesGroup.templates[filePath] = textContent; // save cache
|
||||
templatesGroup.templates.set(filePath, textContent); // save cache
|
||||
|
||||
return textContent;
|
||||
} catch (error) {
|
||||
|
||||
@ -41,7 +41,6 @@ type SelectOptionTemplate = SelectOption<SelectOptionTemplateValue>;
|
||||
interface SelectOptionTemplateValue {
|
||||
sourceFolder: string;
|
||||
filePath: string; // relative to `sourceFolder`
|
||||
content?: string; // available after loading (template selection)
|
||||
}
|
||||
|
||||
@observer
|
||||
@ -115,11 +114,10 @@ export class CreateResource extends React.Component<Props> {
|
||||
return Object.entries(createResourceStore.templateGroups).map(([sourceFolder, group]) => {
|
||||
return {
|
||||
label: group.label,
|
||||
options: Object.entries(group.templates).map(([filePath, content]) => {
|
||||
options: Array.from(group.templates.keys()).map(filePath => {
|
||||
return {
|
||||
label: filePath,
|
||||
value: { filePath, sourceFolder },
|
||||
content,
|
||||
};
|
||||
}),
|
||||
};
|
||||
@ -127,8 +125,8 @@ export class CreateResource extends React.Component<Props> {
|
||||
}
|
||||
|
||||
onSelectTemplate = async ({ value }: SelectOptionTemplate) => {
|
||||
const { filePath, sourceFolder, content } = value;
|
||||
const templateContent = content ?? await createResourceStore.loadTemplate({ filePath, sourceFolder });
|
||||
const { filePath, sourceFolder } = value;
|
||||
const templateContent = await createResourceStore.loadTemplate({ filePath, sourceFolder });
|
||||
|
||||
createResourceStore.setData(this.tabId, templateContent); // update draft
|
||||
};
|
||||
|
||||
@ -89,8 +89,8 @@ export interface DockStorageState {
|
||||
}
|
||||
|
||||
export interface DockTabChangeEvent {
|
||||
tabId?: TabId;
|
||||
tab?: DockTab;
|
||||
tab: DockTab;
|
||||
tabId: TabId;
|
||||
prevTab?: DockTab;
|
||||
}
|
||||
|
||||
@ -212,11 +212,11 @@ export class DockStore implements DockStorageState {
|
||||
});
|
||||
}
|
||||
|
||||
onTabChange(callback?: (evt: DockTabChangeEvent) => void, options: DockTabChangeEventOptions = {}) {
|
||||
onTabChange(callback: (evt: DockTabChangeEvent) => void, options: DockTabChangeEventOptions = {}) {
|
||||
const { tabKind, dockIsVisible = true, ...reactionOpts } = options;
|
||||
|
||||
return reaction(() => this.selectedTab, ((tab, prevTab) => {
|
||||
if (!tab) return; // skip
|
||||
if (!tab) return; // skip when dock is empty
|
||||
if (tabKind && tabKind !== tab.kind) return; // handle specific tab.kind only
|
||||
if (dockIsVisible && !this.isOpen) return;
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ import { observer } from "mobx-react";
|
||||
import { editor, Uri } from "monaco-editor";
|
||||
import { MonacoTheme, registerCustomThemes } from "./monaco-themes";
|
||||
import { MonacoValidator, monacoValidators } from "./monaco-validators";
|
||||
import { cssNames, disposer, toJS } from "../../utils";
|
||||
import { cssNames, disposer, noop, toJS } from "../../utils";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
import { ThemeStore } from "../../theme.store";
|
||||
import debounce from "lodash/debounce";
|
||||
@ -71,6 +71,10 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
public staticId = `editor-id#${Math.round(1e7 * Math.random())}`;
|
||||
public dispose = disposer();
|
||||
|
||||
// TODO: investigate why replacing console.* to common/logger.* calls leads for stucking UI / infinite loop..
|
||||
// e.g. happens on tab change/create, maybe some other cases too.
|
||||
logger = { info: noop, error: noop } as Console;
|
||||
|
||||
@observable.ref containerElem: HTMLElement;
|
||||
@observable.ref editor: editor.IStandaloneCodeEditor;
|
||||
@observable dimensions: { width?: number, height?: number } = {};
|
||||
@ -121,10 +125,8 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
return () => resizeObserver.unobserve(containerElem);
|
||||
}
|
||||
|
||||
// TODO: investigate why replacing console.* to common logger.* calls in a file leads for stucking UI / infinite loop.
|
||||
// e.g. happens on tab change/create, maybe some other cases
|
||||
onModelChange = (model: editor.ITextModel, oldModel?: editor.ITextModel) => {
|
||||
console.info("[MONACO]: model change", { model, oldModel });
|
||||
this.logger.info("[MONACO]: model change", { model, oldModel });
|
||||
|
||||
this.saveViewState(oldModel);
|
||||
this.editor.setModel(model);
|
||||
@ -157,9 +159,9 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
componentDidMount() {
|
||||
try {
|
||||
this.createEditor();
|
||||
console.info(`[MONACO]: editor did mount`);
|
||||
this.logger.info(`[MONACO]: editor did mount`);
|
||||
} catch (error) {
|
||||
console.error(`[MONACO]: mounting failed: ${error}`, this);
|
||||
this.logger.error(`[MONACO]: mounting failed: ${error}`, this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +187,7 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
...this.options,
|
||||
});
|
||||
|
||||
console.info(`[MONACO]: editor created for language=${language}, theme=${theme}`);
|
||||
this.logger.info(`[MONACO]: editor created for language=${language}, theme=${theme}`);
|
||||
this.validateLazy(); // validate initial value
|
||||
this.restoreViewState(); // restore previous state if any
|
||||
|
||||
@ -231,7 +233,6 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
||||
|
||||
@action
|
||||
setDimensions(width: number, height: number) {
|
||||
console.info(`[MONACO]: refreshing dimensions to width=${width} and height=${height}`);
|
||||
this.dimensions.width = width;
|
||||
this.dimensions.height = height;
|
||||
this.editor?.layout({ width, height });
|
||||
|
||||
@ -31,7 +31,7 @@ export interface MonacoThemeData extends editor.IStandaloneThemeData {
|
||||
}
|
||||
|
||||
// Registered names could be then used in "themes/*.json" in "{monacoTheme: [name]}"
|
||||
export const customThemes: Partial<Record<MonacoTheme, MonacoThemeData>> = {
|
||||
export const customThemes: Partial<Record<MonacoCustomTheme, MonacoThemeData>> = {
|
||||
"clouds-midnight": cloudsMidnight as MonacoThemeData,
|
||||
};
|
||||
|
||||
|
||||
@ -23,15 +23,14 @@ import { computed, makeObservable, observable, reaction } from "mobx";
|
||||
import { autoBind, Singleton } from "./utils";
|
||||
import { UserStore } from "../common/user-store";
|
||||
import logger from "../main/logger";
|
||||
import lensDarkTheme from "./themes/lens-dark.json";
|
||||
import lensLightTheme from "./themes/lens-light.json";
|
||||
import lensDarkThemeJson from "./themes/lens-dark.json";
|
||||
import lensLightThemeJson from "./themes/lens-light.json";
|
||||
import type { SelectOption } from "./components/select";
|
||||
import type { MonacoEditorProps } from "./components/monaco-editor";
|
||||
|
||||
export type ThemeId = string;
|
||||
|
||||
export interface Theme {
|
||||
id?: ThemeId;
|
||||
name: string;
|
||||
type: "dark" | "light";
|
||||
colors: Record<string, string>;
|
||||
@ -45,34 +44,23 @@ export class ThemeStore extends Singleton {
|
||||
protected styles: HTMLStyleElement;
|
||||
|
||||
// bundled themes from `themes/${themeId}.json`
|
||||
private allThemes = observable.map<string, Theme>({
|
||||
"lens-dark": lensDarkTheme as Theme,
|
||||
"lens-light": lensLightTheme as Theme,
|
||||
private themes = observable.map<ThemeId, Theme>({
|
||||
"lens-dark": lensDarkThemeJson as Theme,
|
||||
"lens-light": lensLightThemeJson as Theme,
|
||||
});
|
||||
|
||||
@computed get themes() {
|
||||
return Array.from(this.allThemes.entries()).map(([themeId, themeOriginal]) => {
|
||||
const theme: Required<Theme> = {
|
||||
id: themeId, // take id from map's key
|
||||
...themeOriginal,
|
||||
};
|
||||
|
||||
return theme;
|
||||
});
|
||||
}
|
||||
|
||||
@computed get activeThemeId(): string {
|
||||
return UserStore.getInstance().colorTheme;
|
||||
}
|
||||
|
||||
@computed get activeTheme(): Theme {
|
||||
return this.allThemes.get(this.activeThemeId) ?? this.allThemes.get(ThemeStore.defaultTheme);
|
||||
return this.themes.get(this.activeThemeId) ?? this.themes.get(ThemeStore.defaultTheme);
|
||||
}
|
||||
|
||||
@computed get themeOptions(): SelectOption<string>[] {
|
||||
return this.themes.map(theme => ({
|
||||
return Array.from(this.themes).map(([themeId, theme]) => ({
|
||||
label: theme.name,
|
||||
value: theme.id,
|
||||
value: themeId,
|
||||
}));
|
||||
}
|
||||
|
||||
@ -96,7 +84,7 @@ export class ThemeStore extends Singleton {
|
||||
}
|
||||
|
||||
getThemeById(themeId: ThemeId): Theme {
|
||||
return this.allThemes.get(themeId);
|
||||
return this.themes.get(themeId);
|
||||
}
|
||||
|
||||
protected applyTheme(theme: Theme) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user