From 58ffb8e3e45aff6bc659b55154526ee451c1370e Mon Sep 17 00:00:00 2001 From: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com> Date: Tue, 11 Jan 2022 09:35:55 -0500 Subject: [PATCH 1/7] ensure old, saved port-forwards get loaded (#4668) Signed-off-by: Jim Ehrismann --- src/renderer/port-forward/port-forward.store.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/port-forward/port-forward.store.ts b/src/renderer/port-forward/port-forward.store.ts index e19371a65e..e914fff7d5 100644 --- a/src/renderer/port-forward/port-forward.store.ts +++ b/src/renderer/port-forward/port-forward.store.ts @@ -47,14 +47,14 @@ export class PortForwardStore extends ItemStore { const savedPortForwards = this.storage.get(); // undefined on first load - if (Array.isArray(savedPortForwards)) { + if (Array.isArray(savedPortForwards) && savedPortForwards.length > 0) { logger.info("[PORT-FORWARD-STORE] starting saved port-forwards"); // add the disabled ones await Promise.all(savedPortForwards.filter(pf => pf.status === "Disabled").map(addPortForward)); - // add the active ones and check if they started successfully - const results = await Promise.allSettled(savedPortForwards.filter(pf => pf.status === "Active").map(addPortForward)); + // add the active ones (assume active if the status is undefined, for backward compatibilty) and check if they started successfully + const results = await Promise.allSettled(savedPortForwards.filter(pf => !pf.status || pf.status === "Active").map(addPortForward)); for (const result of results) { if (result.status === "rejected" || result.value.status === "Disabled") { From d40071a9d5fa38900199cab4e09f538bf8ff68b2 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 11 Jan 2022 11:58:23 -0500 Subject: [PATCH 2/7] Fix CommandOverlay for extension API (#4673) --- ...egacy-global-function-for-extension-api.ts | 48 +++++++++++++++ ...-legacy-global-object-for-extension-api.ts | 57 ++++++++++++++++++ ...gacy-global-singleton-for-extension-api.ts | 59 +++++++++++++++++++ .../legacy-global-di-for-extension-api.ts | 29 +++++++++ src/extensions/renderer-api/components.ts | 5 +- src/renderer/getDi.tsx | 12 +++- 6 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api.ts create mode 100644 src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api.ts create mode 100644 src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-singleton-for-extension-api.ts create mode 100644 src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts diff --git a/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api.ts new file mode 100644 index 0000000000..8552cb5ec8 --- /dev/null +++ b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api.ts @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import type { Injectable } from "@ogre-tools/injectable"; + +import { getLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api"; + +type TentativeTuple = T extends object ? [T] : [undefined?]; + +type FactoryType = < + TInjectable extends Injectable, + TInstantiationParameter, + TInstance extends (...args: unknown[]) => any, + TFunction extends (...args: unknown[]) => any = Awaited< + ReturnType + >, +>( + injectableKey: TInjectable, + ...instantiationParameter: TentativeTuple +) => (...args: Parameters) => ReturnType; + +export const asLegacyGlobalFunctionForExtensionApi: FactoryType = + (injectableKey, ...instantiationParameter) => + (...args) => { + const injected = getLegacyGlobalDiForExtensionApi().inject( + injectableKey, + ...instantiationParameter, + ); + + return injected(...args); + }; diff --git a/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api.ts new file mode 100644 index 0000000000..9c95472258 --- /dev/null +++ b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api.ts @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import type { Injectable } from "@ogre-tools/injectable"; +import { getLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api"; + +type TentativeTuple = T extends object ? [T] : [undefined?]; + +export const asLegacyGlobalObjectForExtensionApi = < + TInjectable extends Injectable, + TInstantiationParameter, +>( + injectableKey: TInjectable, + ...instantiationParameter: TentativeTuple + ) => + new Proxy( + {}, + { + get(target, propertyName) { + if (propertyName === "$$typeof") { + return undefined; + } + + const instance: any = getLegacyGlobalDiForExtensionApi().inject( + injectableKey, + ...instantiationParameter, + ); + + const propertyValue = instance[propertyName]; + + if (typeof propertyValue === "function") { + return function (...args: any[]) { + return propertyValue.apply(instance, args); + }; + } + + return propertyValue; + }, + }, + ) as ReturnType; diff --git a/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-singleton-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-singleton-for-extension-api.ts new file mode 100644 index 0000000000..a470c6914b --- /dev/null +++ b/src/extensions/as-legacy-globals-for-extension-api/as-legacy-global-singleton-for-extension-api.ts @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import type { Injectable } from "@ogre-tools/injectable"; +import { getLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api"; + +type TentativeTuple = T extends object ? [T] : [undefined?]; + +export const asLegacyGlobalSingletonForExtensionApi = < + TClass extends abstract new (...args: any[]) => any, + TInjectable extends Injectable, + TInstantiationParameter, +>( + Class: TClass, + injectableKey: TInjectable, + ...instantiationParameter: TentativeTuple + ) => + new Proxy(Class, { + construct: () => { + throw new Error("A legacy singleton class must be created by createInstance()"); + }, + + get: (target: any, propertyName) => { + if (propertyName === "getInstance" || propertyName === "createInstance") { + return () => + getLegacyGlobalDiForExtensionApi().inject( + injectableKey, + ...instantiationParameter, + ); + } + + if (propertyName === "resetInstance") { + return () => getLegacyGlobalDiForExtensionApi().purge(injectableKey); + } + + return target[propertyName]; + }, + }) as InstanceType & { + getInstance: () => InstanceType; + createInstance: () => InstanceType; + resetInstance: () => void; + }; diff --git a/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts b/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts new file mode 100644 index 0000000000..0d9bc728a5 --- /dev/null +++ b/src/extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import type { DependencyInjectionContainer } from "@ogre-tools/injectable"; + +let legacyGlobalDi: DependencyInjectionContainer; + +export const setLegacyGlobalDiForExtensionApi = (di: DependencyInjectionContainer) => { + legacyGlobalDi = di; +}; + +export const getLegacyGlobalDiForExtensionApi = () => legacyGlobalDi; diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index 7173b592b3..ad31884330 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -19,6 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import commandOverlayInjectable from "../../renderer/components/command-palette/command-overlay.injectable"; +import { asLegacyGlobalObjectForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; + // layouts export * from "../../renderer/components/layout/main-layout"; export * from "../../renderer/components/layout/setting-layout"; @@ -36,7 +39,7 @@ export * from "../../renderer/components/switch"; export * from "../../renderer/components/input/input"; // command-overlay -export { CommandOverlay } from "../../renderer/components/command-palette"; +export const CommandOverlay = asLegacyGlobalObjectForExtensionApi(commandOverlayInjectable); // other components export * from "../../renderer/components/icon"; diff --git a/src/renderer/getDi.tsx b/src/renderer/getDi.tsx index 4c4359fe74..e9126d62a9 100644 --- a/src/renderer/getDi.tsx +++ b/src/renderer/getDi.tsx @@ -20,14 +20,20 @@ */ import { createContainer } from "@ogre-tools/injectable"; +import { setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; -export const getDi = () => - createContainer( +export function getDi() { + const di = createContainer( getRequireContextForRendererCode, - getRequireContextForCommonCode, getRequireContextForCommonExtensionCode, + getRequireContextForCommonCode, ); + setLegacyGlobalDiForExtensionApi(di); + + return di; +} + const getRequireContextForRendererCode = () => require.context("./", true, /\.injectable\.(ts|tsx)$/); From 14b30d84a1bb7a80a217989ba487ab9804704874 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 12 Jan 2022 07:05:27 -0500 Subject: [PATCH 3/7] Fix crash for KubeObjectStore.loadAll() (#4675) Signed-off-by: Sebastian Malton --- src/common/k8s-api/kube-object.store.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/k8s-api/kube-object.store.ts b/src/common/k8s-api/kube-object.store.ts index 1eb7d9ff50..8f82b9e92a 100644 --- a/src/common/k8s-api/kube-object.store.ts +++ b/src/common/k8s-api/kube-object.store.ts @@ -238,8 +238,9 @@ export abstract class KubeObjectStore extends ItemStore } @action - async loadAll({ namespaces = this.context.contextNamespaces, merge = true, reqInit, onLoadFailure }: KubeObjectStoreLoadAllParams = {}): Promise { + async loadAll({ namespaces, merge = true, reqInit, onLoadFailure }: KubeObjectStoreLoadAllParams = {}): Promise { await this.contextReady; + namespaces ??= this.context.contextNamespaces; this.isLoading = true; try { From 39beca06398e61cb1547466edbbe9e9c26cab2e8 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 12 Jan 2022 07:06:54 -0500 Subject: [PATCH 4/7] Fix Kubectl.downloadKubectl() (#4674) Signed-off-by: Sebastian Malton --- src/main/kubectl.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index 3c3a610807..88daa10b80 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -35,6 +35,7 @@ import { AppPaths } from "../common/app-paths"; import got from "got/dist/source"; import { promisify } from "util"; import stream from "stream"; +import { noop } from "../renderer/utils"; const bundledVersion = getBundledKubectlVersion(); const kubectlMap: Map = new Map([ @@ -315,8 +316,14 @@ export class Kubectl { const fileWriteStream = fs.createWriteStream(this.path, { mode: 0o755 }); const pipeline = promisify(stream.pipeline); - await pipeline(downloadStream, fileWriteStream); - logger.debug("kubectl binary download finished"); + try { + await pipeline(downloadStream, fileWriteStream); + await fs.promises.chmod(this.path, 0o755); + logger.debug("kubectl binary download finished"); + } catch (error) { + await fs.promises.unlink(this.path).catch(noop); + throw error; + } } protected async writeInitScripts() { From 2ee47a442a56d4cd128e34e4d49aeb3ce954c63c Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 12 Jan 2022 08:47:42 -0500 Subject: [PATCH 5/7] Reroute to landing page from previously registered extension cluster pages (#4385) --- src/extensions/registries/page-registry.ts | 5 +--- src/renderer/cluster-frame.tsx | 7 +++-- src/renderer/components/+404/index.ts | 22 -------------- src/renderer/components/+404/not-found.tsx | 35 ---------------------- 4 files changed, 6 insertions(+), 63 deletions(-) delete mode 100644 src/renderer/components/+404/index.ts delete mode 100644 src/renderer/components/+404/not-found.tsx diff --git a/src/extensions/registries/page-registry.ts b/src/extensions/registries/page-registry.ts index aa788681d5..5604538a91 100644 --- a/src/extensions/registries/page-registry.ts +++ b/src/extensions/registries/page-registry.ts @@ -135,10 +135,7 @@ class PageRegistry extends BaseRegistry { ); if (notAStringValue && !(parse || stringify)) { - throw new Error( - `PageRegistry: param's "${paramName}" initialization has failed: - paramInit.parse() and paramInit.stringify() are required for non string | string[] "defaultValue"`, - ); + throw new Error(`PageRegistry: param's "${paramName}" initialization has failed: paramInit.parse() and paramInit.stringify() are required for non string | string[] "defaultValue"`); } paramInit.defaultValue = value; diff --git a/src/renderer/cluster-frame.tsx b/src/renderer/cluster-frame.tsx index 5113377116..bcade8cf5d 100755 --- a/src/renderer/cluster-frame.tsx +++ b/src/renderer/cluster-frame.tsx @@ -23,7 +23,6 @@ import { observable, makeObservable, when } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { Redirect, Route, Router, Switch } from "react-router"; import { history } from "./navigation"; -import { NotFound } from "./components/+404"; import { UserManagement } from "./components/+user-management/user-management"; import { ConfirmDialog } from "./components/confirm-dialog"; import { ClusterOverview } from "./components/+cluster/cluster-overview"; @@ -230,7 +229,11 @@ export class ClusterFrame extends React.Component { {this.renderExtensionTabLayoutRoutes()} {this.renderExtensionRoutes()} - + { + Notifications.error(`Unknown location ${location.pathname}, redirecting to main page.`); + + return ; + }} /> diff --git a/src/renderer/components/+404/index.ts b/src/renderer/components/+404/index.ts deleted file mode 100644 index f0b33889c2..0000000000 --- a/src/renderer/components/+404/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -export * from "./not-found"; diff --git a/src/renderer/components/+404/not-found.tsx b/src/renderer/components/+404/not-found.tsx deleted file mode 100644 index 25f8756afd..0000000000 --- a/src/renderer/components/+404/not-found.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -import React from "react"; -import { TabLayout } from "../layout/tab-layout"; - -export class NotFound extends React.Component { - render() { - return ( - -

- Page not found -

-
- ); - } -} From a5e89b79d671968df3e44e47b26178ebb10c83e8 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 12 Jan 2022 16:42:51 +0100 Subject: [PATCH 6/7] Allow to customize terminal theme (#4666) Allow to customize terminal theme, fix #2224 --- src/common/user-store/preferences-helpers.ts | 10 ++++ src/common/user-store/user-store.ts | 3 + .../components/+preferences/application.tsx | 24 ++++++-- src/renderer/components/dock/dock.scss | 5 +- src/renderer/components/dock/dock.tsx | 2 +- src/renderer/components/dock/terminal.ts | 25 ++------ src/renderer/theme.store.ts | 60 +++++++++++++------ src/renderer/themes/lens-dark.json | 2 +- src/renderer/themes/lens-light.json | 40 ++++++------- 9 files changed, 106 insertions(+), 65 deletions(-) diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index 1ded307f0d..e20e259556 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -83,6 +83,15 @@ const colorTheme: PreferenceDescription = { }, }; +const terminalTheme: PreferenceDescription = { + fromStore(val) { + return val || ""; + }, + toStore(val) { + return val || undefined; + }, +}; + const localeTimezone: PreferenceDescription = { fromStore(val) { return val || moment.tz.guess(true) || "UTC"; @@ -351,6 +360,7 @@ export const DESCRIPTORS = { httpsProxy, shell, colorTheme, + terminalTheme, localeTimezone, allowUntrustedCAs, allowTelemetry, diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index 31238f0ded..952ca32ecc 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -67,6 +67,7 @@ export class UserStore extends BaseStore /* implements UserStore @observable allowErrorReporting: boolean; @observable allowUntrustedCAs: boolean; @observable colorTheme: string; + @observable terminalTheme: string; @observable localeTimezone: string; @observable downloadMirror: string; @observable httpsProxy?: string; @@ -188,6 +189,7 @@ export class UserStore extends BaseStore /* implements UserStore this.httpsProxy = DESCRIPTORS.httpsProxy.fromStore(preferences?.httpsProxy); this.shell = DESCRIPTORS.shell.fromStore(preferences?.shell); this.colorTheme = DESCRIPTORS.colorTheme.fromStore(preferences?.colorTheme); + this.terminalTheme = DESCRIPTORS.terminalTheme.fromStore(preferences?.terminalTheme); this.localeTimezone = DESCRIPTORS.localeTimezone.fromStore(preferences?.localeTimezone); this.allowUntrustedCAs = DESCRIPTORS.allowUntrustedCAs.fromStore(preferences?.allowUntrustedCAs); this.allowTelemetry = DESCRIPTORS.allowTelemetry.fromStore(preferences?.allowTelemetry); @@ -212,6 +214,7 @@ export class UserStore extends BaseStore /* implements UserStore httpsProxy: DESCRIPTORS.httpsProxy.toStore(this.httpsProxy), shell: DESCRIPTORS.shell.toStore(this.shell), colorTheme: DESCRIPTORS.colorTheme.toStore(this.colorTheme), + terminalTheme: DESCRIPTORS.terminalTheme.toStore(this.terminalTheme), localeTimezone: DESCRIPTORS.localeTimezone.toStore(this.localeTimezone), allowUntrustedCAs: DESCRIPTORS.allowUntrustedCAs.toStore(this.allowUntrustedCAs), allowTelemetry: DESCRIPTORS.allowTelemetry.toStore(this.allowTelemetry), diff --git a/src/renderer/components/+preferences/application.tsx b/src/renderer/components/+preferences/application.tsx index 1e3c75b68f..dd2d1bee90 100644 --- a/src/renderer/components/+preferences/application.tsx +++ b/src/renderer/components/+preferences/application.tsx @@ -57,24 +57,38 @@ export const Application = observer(() => { const [customUrl, setCustomUrl] = React.useState(userStore.extensionRegistryUrl.customUrl || ""); const [shell, setShell] = React.useState(userStore.shell || ""); const extensionSettings = AppPreferenceRegistry.getInstance().getItems().filter((preference) => preference.showInPreferencesTab === "application"); + const themeStore = ThemeStore.getInstance(); return (

Application

- + userStore.terminalTheme = value} + /> +
- + {
-
+
diff --git a/src/renderer/components/dock/dock.scss b/src/renderer/components/dock/dock.scss index d473a089fa..49bbcdf6b3 100644 --- a/src/renderer/components/dock/dock.scss +++ b/src/renderer/components/dock/dock.scss @@ -76,11 +76,14 @@ .tab-content { position: relative; - background: var(--terminalBackground); flex: 1; overflow: hidden; transition: flex-basis 25ms ease-in; + &.terminal { + background: var(--terminalBackground); + } + > *:not(.Spinner) { position: absolute; left: 0; diff --git a/src/renderer/components/dock/dock.tsx b/src/renderer/components/dock/dock.tsx index 747fd37a5c..90dc49c478 100644 --- a/src/renderer/components/dock/dock.tsx +++ b/src/renderer/components/dock/dock.tsx @@ -105,7 +105,7 @@ export class Dock extends React.Component { if (!isOpen || !selectedTab) return null; return ( -
+
{this.renderTab(selectedTab)}
); diff --git a/src/renderer/components/dock/terminal.ts b/src/renderer/components/dock/terminal.ts index 383accab20..7028081784 100644 --- a/src/renderer/components/dock/terminal.ts +++ b/src/renderer/components/dock/terminal.ts @@ -26,9 +26,9 @@ import { FitAddon } from "xterm-addon-fit"; import { dockStore, TabId } from "./dock.store"; import { TerminalApi, TerminalChannels } from "../../api/terminal-api"; import { ThemeStore } from "../../theme.store"; -import { boundMethod, disposer } from "../../utils"; +import { disposer } from "../../utils"; import { isMac } from "../../../common/vars"; -import { camelCase, once } from "lodash"; +import { once } from "lodash"; import { UserStore } from "../../../common/user-store"; import { clipboard } from "electron"; import logger from "../../../common/logger"; @@ -56,23 +56,6 @@ export class Terminal { private scrollPos = 0; private disposer = disposer(); - @boundMethod - protected setTheme(colors: Record) { - if (!this.xterm) { - return; - } - - // Replacing keys stored in styles to format accepted by terminal - // E.g. terminalBrightBlack -> brightBlack - const colorPrefix = "terminal"; - const terminalColorEntries = Object.entries(colors) - .filter(([name]) => name.startsWith(colorPrefix)) - .map(([name, color]) => [camelCase(name.slice(colorPrefix.length)), color]); - const terminalColors = Object.fromEntries(terminalColorEntries); - - this.xterm.setOption("theme", terminalColors); - } - get elem() { return this.xterm?.element; } @@ -121,7 +104,9 @@ export class Terminal { window.addEventListener("resize", this.onResize); this.disposer.push( - reaction(() => ThemeStore.getInstance().activeTheme.colors, this.setTheme, { + reaction(() => ThemeStore.getInstance().xtermColors, colors => { + this.xterm?.setOption("theme", colors); + }, { fireImmediately: true, }), dockStore.onResize(this.onResize), diff --git a/src/renderer/theme.store.ts b/src/renderer/theme.store.ts index 15aa055f92..f39a500c71 100644 --- a/src/renderer/theme.store.ts +++ b/src/renderer/theme.store.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { computed, makeObservable, observable, reaction } from "mobx"; +import { comparer, computed, makeObservable, observable, reaction } from "mobx"; import { autoBind, Singleton } from "./utils"; import { UserStore } from "../common/user-store"; import logger from "../main/logger"; @@ -28,6 +28,7 @@ import lensLightThemeJson from "./themes/lens-light.json"; import type { SelectOption } from "./components/select"; import type { MonacoEditorProps } from "./components/monaco-editor"; import { defaultTheme } from "../common/vars"; +import { camelCase } from "lodash"; export type ThemeId = string; @@ -41,7 +42,7 @@ export interface Theme { } export class ThemeStore extends Singleton { - protected styles: HTMLStyleElement; + private terminalColorPrefix = "terminal"; // bundled themes from `themes/${themeId}.json` private themes = observable.map({ @@ -49,14 +50,37 @@ export class ThemeStore extends Singleton { "lens-light": lensLightThemeJson as Theme, }); - @computed get activeThemeId(): string { + @computed get activeThemeId(): ThemeId { return UserStore.getInstance().colorTheme; } + @computed get terminalThemeId(): ThemeId { + return UserStore.getInstance().terminalTheme; + } + @computed get activeTheme(): Theme { return this.themes.get(this.activeThemeId) ?? this.themes.get(defaultTheme); } + @computed get terminalColors(): [string, string][] { + const theme = this.themes.get(this.terminalThemeId) ?? this.activeTheme; + + return Object + .entries(theme.colors) + .filter(([name]) => name.startsWith(this.terminalColorPrefix)); + } + + // Replacing keys stored in styles to format accepted by terminal + // E.g. terminalBrightBlack -> brightBlack + @computed get xtermColors(): Record { + return Object.fromEntries( + this.terminalColors.map(([name, color]) => [ + camelCase(name.replace(this.terminalColorPrefix, "")), + color, + ]), + ); + } + @computed get themeOptions(): SelectOption[] { return Array.from(this.themes).map(([themeId, theme]) => ({ label: theme.name, @@ -71,15 +95,19 @@ export class ThemeStore extends Singleton { autoBind(this); // auto-apply active theme - reaction(() => this.activeThemeId, themeId => { + reaction(() => ({ + themeId: this.activeThemeId, + terminalThemeId: this.terminalThemeId, + }), ({ themeId }) => { try { - this.applyTheme(this.getThemeById(themeId)); + this.applyTheme(themeId); } catch (err) { logger.error(err); UserStore.getInstance().resetTheme(); } }, { fireImmediately: true, + equals: comparer.shallow, }); } @@ -87,20 +115,18 @@ export class ThemeStore extends Singleton { return this.themes.get(themeId); } - protected applyTheme(theme: Theme) { - if (!this.styles) { - this.styles = document.createElement("style"); - this.styles.id = "lens-theme"; - document.head.append(this.styles); - } - const cssVars = Object.entries(theme.colors).map(([cssName, color]) => { - return `--${cssName}: ${color};`; + protected applyTheme(themeId: ThemeId) { + const theme = this.getThemeById(themeId); + const colors = Object.entries({ + ...theme.colors, + ...Object.fromEntries(this.terminalColors), }); - this.styles.textContent = `:root {\n${cssVars.join("\n")}}`; - // Adding universal theme flag which can be used in component styles - const body = document.querySelector("body"); + colors.forEach(([name, value]) => { + document.documentElement.style.setProperty(`--${name}`, value); + }); - body.classList.toggle("theme-light", theme.type === "light"); + // Adding universal theme flag which can be used in component styles + document.body.classList.toggle("theme-light", theme.type === "light"); } } diff --git a/src/renderer/themes/lens-dark.json b/src/renderer/themes/lens-dark.json index 023f9f6ccf..b48ed84cc7 100644 --- a/src/renderer/themes/lens-dark.json +++ b/src/renderer/themes/lens-dark.json @@ -1,5 +1,5 @@ { - "name": "Dark (Lens)", + "name": "Dark", "type": "dark", "description": "Original Lens dark theme", "author": "Mirantis", diff --git a/src/renderer/themes/lens-light.json b/src/renderer/themes/lens-light.json index 8525d31a56..7891f53321 100644 --- a/src/renderer/themes/lens-light.json +++ b/src/renderer/themes/lens-light.json @@ -1,5 +1,5 @@ { - "name": "Light (Lens)", + "name": "Light", "type": "light", "description": "Original Lens light theme", "author": "Mirantis", @@ -76,26 +76,26 @@ "logsBackground": "#24292e", "logsForeground": "#ffffff", "logRowHoverBackground": "#35373a", - "terminalBackground": "#24292e", - "terminalForeground": "#ffffff", - "terminalCursor": "#ffffff", - "terminalCursorAccent": "#000000", - "terminalSelection": "#ffffff77", - "terminalBlack": "#2e3436", - "terminalRed": "#cc0000", - "terminalGreen": "#4e9a06", - "terminalYellow": "#c4a000", - "terminalBlue": "#3465a4", - "terminalMagenta": "#75507b", - "terminalCyan": "#06989a", + "terminalBackground": "#ffffff", + "terminalForeground": "#2d2d2d", + "terminalCursor": "#2d2d2d", + "terminalCursorAccent": "#ffffff", + "terminalSelection": "#bfbfbf", + "terminalBlack": "#2d2d2d", + "terminalRed": "#cd3734 ", + "terminalGreen": "#18cf12", + "terminalYellow": "#acb300", + "terminalBlue": "#3d90ce", + "terminalMagenta": "#c100cd", + "terminalCyan": "#07c4b9", "terminalWhite": "#d3d7cf", - "terminalBrightBlack": "#555753", - "terminalBrightRed": "#ef2929", - "terminalBrightGreen": "#8ae234", - "terminalBrightYellow": "#fce94f", - "terminalBrightBlue": "#729fcf", - "terminalBrightMagenta": "#ad7fa8", - "terminalBrightCyan": "#34e2e2", + "terminalBrightBlack": "#a8a8a8", + "terminalBrightRed": "#ff6259", + "terminalBrightGreen": "#5cdb59", + "terminalBrightYellow": "#f8c000", + "terminalBrightBlue": "#008db6", + "terminalBrightMagenta": "#ee55f8", + "terminalBrightCyan": "#50e8df", "terminalBrightWhite": "#eeeeec", "dialogTextColor": "#87909c", "dialogBackground": "#ffffff", From 0be1ab4ce0a15994b343bcb67d050d85016ab26d Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 13 Jan 2022 11:54:54 +0100 Subject: [PATCH 7/7] Revert "Allow to customize terminal theme (#4666)" (#4682) This reverts commit a5e89b79d671968df3e44e47b26178ebb10c83e8. --- src/common/user-store/preferences-helpers.ts | 10 ---- src/common/user-store/user-store.ts | 3 - .../components/+preferences/application.tsx | 24 ++------ src/renderer/components/dock/dock.scss | 5 +- src/renderer/components/dock/dock.tsx | 2 +- src/renderer/components/dock/terminal.ts | 25 ++++++-- src/renderer/theme.store.ts | 60 ++++++------------- src/renderer/themes/lens-dark.json | 2 +- src/renderer/themes/lens-light.json | 40 ++++++------- 9 files changed, 65 insertions(+), 106 deletions(-) diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index e20e259556..1ded307f0d 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -83,15 +83,6 @@ const colorTheme: PreferenceDescription = { }, }; -const terminalTheme: PreferenceDescription = { - fromStore(val) { - return val || ""; - }, - toStore(val) { - return val || undefined; - }, -}; - const localeTimezone: PreferenceDescription = { fromStore(val) { return val || moment.tz.guess(true) || "UTC"; @@ -360,7 +351,6 @@ export const DESCRIPTORS = { httpsProxy, shell, colorTheme, - terminalTheme, localeTimezone, allowUntrustedCAs, allowTelemetry, diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index 952ca32ecc..31238f0ded 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -67,7 +67,6 @@ export class UserStore extends BaseStore /* implements UserStore @observable allowErrorReporting: boolean; @observable allowUntrustedCAs: boolean; @observable colorTheme: string; - @observable terminalTheme: string; @observable localeTimezone: string; @observable downloadMirror: string; @observable httpsProxy?: string; @@ -189,7 +188,6 @@ export class UserStore extends BaseStore /* implements UserStore this.httpsProxy = DESCRIPTORS.httpsProxy.fromStore(preferences?.httpsProxy); this.shell = DESCRIPTORS.shell.fromStore(preferences?.shell); this.colorTheme = DESCRIPTORS.colorTheme.fromStore(preferences?.colorTheme); - this.terminalTheme = DESCRIPTORS.terminalTheme.fromStore(preferences?.terminalTheme); this.localeTimezone = DESCRIPTORS.localeTimezone.fromStore(preferences?.localeTimezone); this.allowUntrustedCAs = DESCRIPTORS.allowUntrustedCAs.fromStore(preferences?.allowUntrustedCAs); this.allowTelemetry = DESCRIPTORS.allowTelemetry.fromStore(preferences?.allowTelemetry); @@ -214,7 +212,6 @@ export class UserStore extends BaseStore /* implements UserStore httpsProxy: DESCRIPTORS.httpsProxy.toStore(this.httpsProxy), shell: DESCRIPTORS.shell.toStore(this.shell), colorTheme: DESCRIPTORS.colorTheme.toStore(this.colorTheme), - terminalTheme: DESCRIPTORS.terminalTheme.toStore(this.terminalTheme), localeTimezone: DESCRIPTORS.localeTimezone.toStore(this.localeTimezone), allowUntrustedCAs: DESCRIPTORS.allowUntrustedCAs.toStore(this.allowUntrustedCAs), allowTelemetry: DESCRIPTORS.allowTelemetry.toStore(this.allowTelemetry), diff --git a/src/renderer/components/+preferences/application.tsx b/src/renderer/components/+preferences/application.tsx index dd2d1bee90..1e3c75b68f 100644 --- a/src/renderer/components/+preferences/application.tsx +++ b/src/renderer/components/+preferences/application.tsx @@ -57,38 +57,24 @@ export const Application = observer(() => { const [customUrl, setCustomUrl] = React.useState(userStore.extensionRegistryUrl.customUrl || ""); const [shell, setShell] = React.useState(userStore.shell || ""); const extensionSettings = AppPreferenceRegistry.getInstance().getItems().filter((preference) => preference.showInPreferencesTab === "application"); - const themeStore = ThemeStore.getInstance(); return (

Application

- + userStore.terminalTheme = value} - /> -
+
- + {
-
+
diff --git a/src/renderer/components/dock/dock.scss b/src/renderer/components/dock/dock.scss index 49bbcdf6b3..d473a089fa 100644 --- a/src/renderer/components/dock/dock.scss +++ b/src/renderer/components/dock/dock.scss @@ -76,14 +76,11 @@ .tab-content { position: relative; + background: var(--terminalBackground); flex: 1; overflow: hidden; transition: flex-basis 25ms ease-in; - &.terminal { - background: var(--terminalBackground); - } - > *:not(.Spinner) { position: absolute; left: 0; diff --git a/src/renderer/components/dock/dock.tsx b/src/renderer/components/dock/dock.tsx index 90dc49c478..747fd37a5c 100644 --- a/src/renderer/components/dock/dock.tsx +++ b/src/renderer/components/dock/dock.tsx @@ -105,7 +105,7 @@ export class Dock extends React.Component { if (!isOpen || !selectedTab) return null; return ( -
+
{this.renderTab(selectedTab)}
); diff --git a/src/renderer/components/dock/terminal.ts b/src/renderer/components/dock/terminal.ts index 7028081784..383accab20 100644 --- a/src/renderer/components/dock/terminal.ts +++ b/src/renderer/components/dock/terminal.ts @@ -26,9 +26,9 @@ import { FitAddon } from "xterm-addon-fit"; import { dockStore, TabId } from "./dock.store"; import { TerminalApi, TerminalChannels } from "../../api/terminal-api"; import { ThemeStore } from "../../theme.store"; -import { disposer } from "../../utils"; +import { boundMethod, disposer } from "../../utils"; import { isMac } from "../../../common/vars"; -import { once } from "lodash"; +import { camelCase, once } from "lodash"; import { UserStore } from "../../../common/user-store"; import { clipboard } from "electron"; import logger from "../../../common/logger"; @@ -56,6 +56,23 @@ export class Terminal { private scrollPos = 0; private disposer = disposer(); + @boundMethod + protected setTheme(colors: Record) { + if (!this.xterm) { + return; + } + + // Replacing keys stored in styles to format accepted by terminal + // E.g. terminalBrightBlack -> brightBlack + const colorPrefix = "terminal"; + const terminalColorEntries = Object.entries(colors) + .filter(([name]) => name.startsWith(colorPrefix)) + .map(([name, color]) => [camelCase(name.slice(colorPrefix.length)), color]); + const terminalColors = Object.fromEntries(terminalColorEntries); + + this.xterm.setOption("theme", terminalColors); + } + get elem() { return this.xterm?.element; } @@ -104,9 +121,7 @@ export class Terminal { window.addEventListener("resize", this.onResize); this.disposer.push( - reaction(() => ThemeStore.getInstance().xtermColors, colors => { - this.xterm?.setOption("theme", colors); - }, { + reaction(() => ThemeStore.getInstance().activeTheme.colors, this.setTheme, { fireImmediately: true, }), dockStore.onResize(this.onResize), diff --git a/src/renderer/theme.store.ts b/src/renderer/theme.store.ts index f39a500c71..15aa055f92 100644 --- a/src/renderer/theme.store.ts +++ b/src/renderer/theme.store.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { comparer, computed, makeObservable, observable, reaction } from "mobx"; +import { computed, makeObservable, observable, reaction } from "mobx"; import { autoBind, Singleton } from "./utils"; import { UserStore } from "../common/user-store"; import logger from "../main/logger"; @@ -28,7 +28,6 @@ import lensLightThemeJson from "./themes/lens-light.json"; import type { SelectOption } from "./components/select"; import type { MonacoEditorProps } from "./components/monaco-editor"; import { defaultTheme } from "../common/vars"; -import { camelCase } from "lodash"; export type ThemeId = string; @@ -42,7 +41,7 @@ export interface Theme { } export class ThemeStore extends Singleton { - private terminalColorPrefix = "terminal"; + protected styles: HTMLStyleElement; // bundled themes from `themes/${themeId}.json` private themes = observable.map({ @@ -50,37 +49,14 @@ export class ThemeStore extends Singleton { "lens-light": lensLightThemeJson as Theme, }); - @computed get activeThemeId(): ThemeId { + @computed get activeThemeId(): string { return UserStore.getInstance().colorTheme; } - @computed get terminalThemeId(): ThemeId { - return UserStore.getInstance().terminalTheme; - } - @computed get activeTheme(): Theme { return this.themes.get(this.activeThemeId) ?? this.themes.get(defaultTheme); } - @computed get terminalColors(): [string, string][] { - const theme = this.themes.get(this.terminalThemeId) ?? this.activeTheme; - - return Object - .entries(theme.colors) - .filter(([name]) => name.startsWith(this.terminalColorPrefix)); - } - - // Replacing keys stored in styles to format accepted by terminal - // E.g. terminalBrightBlack -> brightBlack - @computed get xtermColors(): Record { - return Object.fromEntries( - this.terminalColors.map(([name, color]) => [ - camelCase(name.replace(this.terminalColorPrefix, "")), - color, - ]), - ); - } - @computed get themeOptions(): SelectOption[] { return Array.from(this.themes).map(([themeId, theme]) => ({ label: theme.name, @@ -95,19 +71,15 @@ export class ThemeStore extends Singleton { autoBind(this); // auto-apply active theme - reaction(() => ({ - themeId: this.activeThemeId, - terminalThemeId: this.terminalThemeId, - }), ({ themeId }) => { + reaction(() => this.activeThemeId, themeId => { try { - this.applyTheme(themeId); + this.applyTheme(this.getThemeById(themeId)); } catch (err) { logger.error(err); UserStore.getInstance().resetTheme(); } }, { fireImmediately: true, - equals: comparer.shallow, }); } @@ -115,18 +87,20 @@ export class ThemeStore extends Singleton { return this.themes.get(themeId); } - protected applyTheme(themeId: ThemeId) { - const theme = this.getThemeById(themeId); - const colors = Object.entries({ - ...theme.colors, - ...Object.fromEntries(this.terminalColors), - }); - - colors.forEach(([name, value]) => { - document.documentElement.style.setProperty(`--${name}`, value); + protected applyTheme(theme: Theme) { + if (!this.styles) { + this.styles = document.createElement("style"); + this.styles.id = "lens-theme"; + document.head.append(this.styles); + } + const cssVars = Object.entries(theme.colors).map(([cssName, color]) => { + return `--${cssName}: ${color};`; }); + this.styles.textContent = `:root {\n${cssVars.join("\n")}}`; // Adding universal theme flag which can be used in component styles - document.body.classList.toggle("theme-light", theme.type === "light"); + const body = document.querySelector("body"); + + body.classList.toggle("theme-light", theme.type === "light"); } } diff --git a/src/renderer/themes/lens-dark.json b/src/renderer/themes/lens-dark.json index b48ed84cc7..023f9f6ccf 100644 --- a/src/renderer/themes/lens-dark.json +++ b/src/renderer/themes/lens-dark.json @@ -1,5 +1,5 @@ { - "name": "Dark", + "name": "Dark (Lens)", "type": "dark", "description": "Original Lens dark theme", "author": "Mirantis", diff --git a/src/renderer/themes/lens-light.json b/src/renderer/themes/lens-light.json index 7891f53321..8525d31a56 100644 --- a/src/renderer/themes/lens-light.json +++ b/src/renderer/themes/lens-light.json @@ -1,5 +1,5 @@ { - "name": "Light", + "name": "Light (Lens)", "type": "light", "description": "Original Lens light theme", "author": "Mirantis", @@ -76,26 +76,26 @@ "logsBackground": "#24292e", "logsForeground": "#ffffff", "logRowHoverBackground": "#35373a", - "terminalBackground": "#ffffff", - "terminalForeground": "#2d2d2d", - "terminalCursor": "#2d2d2d", - "terminalCursorAccent": "#ffffff", - "terminalSelection": "#bfbfbf", - "terminalBlack": "#2d2d2d", - "terminalRed": "#cd3734 ", - "terminalGreen": "#18cf12", - "terminalYellow": "#acb300", - "terminalBlue": "#3d90ce", - "terminalMagenta": "#c100cd", - "terminalCyan": "#07c4b9", + "terminalBackground": "#24292e", + "terminalForeground": "#ffffff", + "terminalCursor": "#ffffff", + "terminalCursorAccent": "#000000", + "terminalSelection": "#ffffff77", + "terminalBlack": "#2e3436", + "terminalRed": "#cc0000", + "terminalGreen": "#4e9a06", + "terminalYellow": "#c4a000", + "terminalBlue": "#3465a4", + "terminalMagenta": "#75507b", + "terminalCyan": "#06989a", "terminalWhite": "#d3d7cf", - "terminalBrightBlack": "#a8a8a8", - "terminalBrightRed": "#ff6259", - "terminalBrightGreen": "#5cdb59", - "terminalBrightYellow": "#f8c000", - "terminalBrightBlue": "#008db6", - "terminalBrightMagenta": "#ee55f8", - "terminalBrightCyan": "#50e8df", + "terminalBrightBlack": "#555753", + "terminalBrightRed": "#ef2929", + "terminalBrightGreen": "#8ae234", + "terminalBrightYellow": "#fce94f", + "terminalBrightBlue": "#729fcf", + "terminalBrightMagenta": "#ad7fa8", + "terminalBrightCyan": "#34e2e2", "terminalBrightWhite": "#eeeeec", "dialogTextColor": "#87909c", "dialogBackground": "#ffffff",