mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Make base store non Singleton (#6690)
* Remove Singleton from BaseStore to remove global shared state Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove more usages of Singleton Signed-off-by: Sebastian Malton <sebastian@malton.name> * Replace use of legacy global execHelm with injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove last use of legacy global execHelm Signed-off-by: Sebastian Malton <sebastian@malton.name> * Extract BaseStore deps into constructor argument Signed-off-by: Sebastian Malton <sebastian@malton.name> * Introduce method to make store migrations injectable - Use it for ClusterStore Signed-off-by: Sebastian Malton <sebastian@malton.name> * Switch HotbarStore to injectable migrations Signed-off-by: Sebastian Malton <sebastian@malton.name> * Switch UserStore to injectable migrations Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move migration utils into common/utils/ Signed-off-by: Sebastian Malton <sebastian@malton.name> * Switch WeblinkStore to injectable migrations Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove dead code Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix type error in base-store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove tests that reference lastSeenVersion - That value is not used anywhere in code Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usage of legacy global .getInstance Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove usage of legacy global ClusterStore.getInstance Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add simple migrations dependency for stores without any preexisting migrations Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix messed up import Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add typing to transient injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cleanup formatting Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix typing in tests to satisfy requirement to have cacheFile Signed-off-by: Sebastian Malton <sebastian@malton.name> * More consistent use of BaseStore.displayName Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add catching of error while starting main application Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move initializing sentry to runnable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove unneeded appPathsInjectionToken - Only had once impl, which was in common anyway Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add support for multiple "runAfter" runnables - Needed so that several dependencies can be declared Signed-off-by: Sebastian Malton <sebastian@malton.name> * Use multiple runAfter support to fix crash on renderer Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove traces Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add global override to fix tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix base store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix runManyFor tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix hotbar store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix user store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add global override for getConfigurationFileModel to fix tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove overrides for configuration stores - Now that there is an override for getConfiguration Signed-off-by: Sebastian Malton <sebastian@malton.name> * Overhaul FS fakes with full in-memory filesystem - This increases our confidence in fs related logic Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove use of global shared Electron.App Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add fake access support Signed-off-by: Sebastian Malton <sebastian@malton.name> * Handle copy as part of fake FS Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add ensureDir/Sync support to fake FS Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix type error Signed-off-by: Sebastian Malton <sebastian@malton.name> * Use pathExistsSync instead of fsInjectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add createReadStream to fake FS Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add stat to fake FS Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove dead code Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix test failures due to incomplete overrides Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fully injectable-ize BaseStore so that ApplicationBuilder tests work Signed-off-by: Sebastian Malton <sebastian@malton.name> * Consolidate more bootstrapping into startFrame Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move initializing CatalogCategories to runnable in bootstrap Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert contextMenuOpen initializers into runnables Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert navigateForExtension init to runnable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make cluster state sync fully injectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Move init hotbar store into runnables Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make LensTheme fully injectable and runnable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cleanup old code from missed from previous commit Signed-off-by: Sebastian Malton <sebastian@malton.name> * Manually split out terminal color names and fully type LensTheme Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix old imports Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove unnecessart awaits Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove dead code Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fully cherry pick injectablizing custom monaco themes Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix duplicate mock warning Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix incorrectly fully cherry picking new runnable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Complete cherry-pick of current cluster injcetablization Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix override file name Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix injecting before app paths are set up Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix injecting before app paths are set up Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix ordering of runnable and order of injection Signed-off-by: Sebastian Malton <sebastian@malton.name> * Convert all renderer runnables to late-inject style - To help fix issues around injection time Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix react-beautiful-dnd mocks Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update and fix WriteJson(Sync) to fix error in tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix HotbarStore.load being called twice is being buggy Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update listing-active-helm-repositories-in-preferences snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix sidebar-and-tab-navigation-tests - Move enabling extensions in tests to a proper location - Fix flushing promises Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove props from dnd mock to make snapshot diffs smaller Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix import Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests by overriding things that are no longer overriden by default - NOTE: They are overridden when using ApplicationBuilder Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix hotbar store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix cluster store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix extension-loader tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix extension-discovery tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix cluster-role-dialog tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix user store tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix kubeconfig sync tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix sidebar and tab tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove unused code Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix pick paths import type error and simplify signature Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix type error in legacy ipc registration Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove another use of legacy requestOpenPathPicker Signed-off-by: Sebastian Malton <sebastian@malton.name> * Replace use of legacy global PathPicker.Pick Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix usage in light of changed prop names Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix catalog tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix more type errors Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix test flakiness by removing side effects from userStore preferences Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix loading Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix type error Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix crash Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cherry pick updated startFrameInjectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add tests to verify runMany behaviour in new possible incorrect configuration Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix init ordering during start frame Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix cluster state sync Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update snapshots after removing side-effects Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add override for technical test Signed-off-by: Sebastian Malton <sebastian@malton.name> * Correctly mark currentlyInClusterFrame as causedSideEffects Signed-off-by: Sebastian Malton <sebastian@malton.name> * Better formatting Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix behaviour regression Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add better logging Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix BaseStore sync Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Update last snapshot Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add global override for randomBytes Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make startMainApplication not an injection time side effect Signed-off-by: Sebastian Malton <sebastian@malton.name> * Choose better names for start-frame runnable tokens Signed-off-by: Sebastian Malton <sebastian@malton.name> * Remove duplication of code in RunManyFor Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add unit tests and fix handling empty runAfter array Signed-off-by: Sebastian Malton <sebastian@malton.name> * Replace use of mobx from runManyFor with custom barrier Signed-off-by: Sebastian Malton <sebastian@malton.name> * Add missing test Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
7c5faaaf1d
commit
25f37ac1d1
364 files changed
+10035
-5246
No files matched your search
@@ -4,28 +4,25 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import appPathsStateInjectable from "../../common/app-paths/app-paths-state.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsFirstInjectionToken } from "../before-frame-starts/tokens";
|
||||
import { appPathsChannel } from "../../common/app-paths/app-paths-channel";
|
||||
import { requestFromChannelInjectionToken } from "../../common/utils/channel/request-from-channel-injection-token";
|
||||
|
||||
const setupAppPathsInjectable = getInjectable({
|
||||
id: "setup-app-paths",
|
||||
|
||||
instantiate: (di) => {
|
||||
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||
const appPathsState = di.inject(appPathsStateInjectable);
|
||||
instantiate: (di) => ({
|
||||
id: "setup-app-paths",
|
||||
run: async () => {
|
||||
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||
const appPathsState = di.inject(appPathsStateInjectable);
|
||||
const appPaths = await requestFromChannel(appPathsChannel);
|
||||
|
||||
return {
|
||||
id: "setup-app-paths",
|
||||
run: async () => {
|
||||
const appPaths = await requestFromChannel(appPathsChannel);
|
||||
appPathsState.set(appPaths);
|
||||
},
|
||||
}),
|
||||
|
||||
appPathsState.set(appPaths);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
injectionToken: beforeFrameStartsFirstInjectionToken,
|
||||
});
|
||||
|
||||
export default setupAppPathsInjectable;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../../common/base-store/disable-sync";
|
||||
|
||||
const shouldBaseStoreDisableSyncInIpcListenerInjectable = getInjectable({
|
||||
id: "should-base-store-disable-sync-in-ipc-listener",
|
||||
instantiate: () => true,
|
||||
injectionToken: shouldBaseStoreDisableSyncInIpcListenerInjectionToken,
|
||||
});
|
||||
|
||||
export default shouldBaseStoreDisableSyncInIpcListenerInjectable;
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { baseStoreIpcChannelPrefixesInjectionToken } from "../../common/base-store/channel-prefix";
|
||||
|
||||
const baseStoreIpcChannelPrefixInjectable = getInjectable({
|
||||
id: "base-store-ipc-channel-prefix",
|
||||
instantiate: () => ({
|
||||
local: "store-sync-renderer",
|
||||
remote: "store-sync-main",
|
||||
}),
|
||||
injectionToken: baseStoreIpcChannelPrefixesInjectionToken,
|
||||
});
|
||||
|
||||
export default baseStoreIpcChannelPrefixInjectable;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { persistStateToConfigInjectionToken } from "../../common/base-store/save-to-file";
|
||||
import { noop } from "../utils";
|
||||
|
||||
const persistStateToConfigInjectable = getInjectable({
|
||||
id: "persist-state-to-config",
|
||||
instantiate: () => noop,
|
||||
injectionToken: persistStateToConfigInjectionToken,
|
||||
});
|
||||
|
||||
export default persistStateToConfigInjectable;
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { Runnable } from "../../common/runnable/run-many-for";
|
||||
|
||||
export const beforeFrameStartsInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "before-frame-starts",
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { setAutoFreeze, enableMapSet } from "immer";
|
||||
import { beforeFrameStartsFirstInjectionToken } from "../tokens";
|
||||
|
||||
const configureImmerInjectable = getInjectable({
|
||||
id: "configure-immer",
|
||||
instantiate: () => ({
|
||||
id: "configure-immer",
|
||||
run: () => {
|
||||
// Docs: https://immerjs.github.io/immer/
|
||||
// Required in `utils/storage-helper.ts`
|
||||
setAutoFreeze(false); // allow to merge mobx observables
|
||||
enableMapSet(); // allow to merge maps and sets
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsFirstInjectionToken,
|
||||
});
|
||||
|
||||
export default configureImmerInjectable;
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { configure } from "mobx";
|
||||
import { beforeFrameStartsFirstInjectionToken } from "../tokens";
|
||||
|
||||
const configureMobxInjectable = getInjectable({
|
||||
id: "configure-mobx",
|
||||
instantiate: () => ({
|
||||
id: "configure-mobx",
|
||||
run: () => {
|
||||
// Docs: https://mobx.js.org/configuration.html
|
||||
configure({
|
||||
enforceActions: "never",
|
||||
|
||||
// TODO: enable later (read more: https://mobx.js.org/migrating-from-4-or-5.html)
|
||||
// computedRequiresReaction: true,
|
||||
// reactionRequiresObservable: true,
|
||||
// observableRequiresReaction: true,
|
||||
});
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsFirstInjectionToken,
|
||||
});
|
||||
|
||||
export default configureMobxInjectable;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { customMonacoThemeInjectionToken } from "../../components/monaco-editor";
|
||||
import addNewMonacoThemeInjectable from "../../monaco/add-new-theme.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../tokens";
|
||||
|
||||
const loadMonacoThemesInjectable = getInjectable({
|
||||
id: "load-monaco-themes",
|
||||
instantiate: (di) => ({
|
||||
id: "load-monaco-themes",
|
||||
run: () => {
|
||||
const customThemes = di.injectMany(customMonacoThemeInjectionToken);
|
||||
const addNewMonacoTheme = di.inject(addNewMonacoThemeInjectable);
|
||||
|
||||
customThemes.forEach(addNewMonacoTheme);
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default loadMonacoThemesInjectable;
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import autoRegistrationEmitterInjectable from "../../../common/k8s-api/api-manager/auto-registration-emitter.injectable";
|
||||
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
|
||||
import { CustomResourceStore } from "../../../common/k8s-api/api-manager/resource.store";
|
||||
import type { CustomResourceDefinition } from "../../../common/k8s-api/endpoints";
|
||||
import { KubeApi } from "../../../common/k8s-api/kube-api";
|
||||
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||
import { beforeClusterFrameStartsInjectionToken } from "../tokens";
|
||||
|
||||
const setupAutoRegistrationInjectable = getInjectable({
|
||||
id: "setup-auto-registration",
|
||||
instantiate: (di) => ({
|
||||
id: "setup-auto-registration",
|
||||
run: () => {
|
||||
const autoRegistrationEmitter = di.inject(autoRegistrationEmitterInjectable);
|
||||
const beforeApiManagerInitializationCrds: CustomResourceDefinition[] = [];
|
||||
const beforeApiManagerInitializationApis: KubeApi[] = [];
|
||||
let initialized = false;
|
||||
|
||||
const autoInitCustomResourceStore = (crd: CustomResourceDefinition) => {
|
||||
const objectConstructor = class extends KubeObject {
|
||||
static readonly kind = crd.getResourceKind();
|
||||
static readonly namespaced = crd.isNamespaced();
|
||||
static readonly apiBase = crd.getResourceApiBase();
|
||||
};
|
||||
|
||||
const api = (() => {
|
||||
const rawApi = apiManager.getApi(objectConstructor.apiBase);
|
||||
|
||||
if (rawApi) {
|
||||
return rawApi;
|
||||
}
|
||||
|
||||
const api = new KubeApi({ objectConstructor });
|
||||
|
||||
apiManager.registerApi(api);
|
||||
|
||||
return api;
|
||||
})();
|
||||
|
||||
if (!apiManager.getStore(api)) {
|
||||
apiManager.registerStore(new CustomResourceStore(api));
|
||||
}
|
||||
};
|
||||
const autoInitKubeApi = (api: KubeApi) => {
|
||||
apiManager.registerApi(api);
|
||||
};
|
||||
|
||||
autoRegistrationEmitter
|
||||
.on("customResourceDefinition", (crd) => {
|
||||
if (initialized) {
|
||||
autoInitCustomResourceStore(crd);
|
||||
} else {
|
||||
beforeApiManagerInitializationCrds.push(crd);
|
||||
}
|
||||
})
|
||||
.on("kubeApi", (api) => {
|
||||
if (initialized) {
|
||||
autoInitKubeApi(api);
|
||||
} else {
|
||||
beforeApiManagerInitializationApis.push(api);
|
||||
}
|
||||
});
|
||||
|
||||
const apiManager = di.inject(apiManagerInjectable);
|
||||
|
||||
beforeApiManagerInitializationCrds.forEach(autoInitCustomResourceStore);
|
||||
beforeApiManagerInitializationApis.forEach(autoInitKubeApi);
|
||||
initialized = true;
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeClusterFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupAutoRegistrationInjectable;
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { reaction } from "mobx";
|
||||
import { currentClusterMessageChannel } from "../../../common/cluster/current-cluster-channel";
|
||||
import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
|
||||
import matchedClusterIdInjectable from "../../navigation/matched-cluster-id.injectable";
|
||||
import { beforeMainFrameStartsInjectionToken } from "../tokens";
|
||||
|
||||
const setupCurrentClusterBroadcastInjectable = getInjectable({
|
||||
id: "setup-current-cluster-broadcast",
|
||||
instantiate: (di) => ({
|
||||
id: "setup-current-cluster-broadcast",
|
||||
run: () => {
|
||||
const matchedClusterId = di.inject(matchedClusterIdInjectable);
|
||||
const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken);
|
||||
|
||||
reaction(
|
||||
() => matchedClusterId.get(),
|
||||
clusterId => sendMessageToChannel(currentClusterMessageChannel, clusterId),
|
||||
{
|
||||
fireImmediately: true,
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeMainFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupCurrentClusterBroadcastInjectable;
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import kubernetesClusterCategoryInjectable from "../../../common/catalog/categories/kubernetes-cluster.injectable";
|
||||
import navigateToAddClusterInjectable from "../../../common/front-end-routing/routes/add-cluster/navigate-to-add-cluster.injectable";
|
||||
import isLinuxInjectable from "../../../common/vars/is-linux.injectable";
|
||||
import isWindowsInjectable from "../../../common/vars/is-windows.injectable";
|
||||
import openPathPickingDialogInjectable from "../../../features/path-picking-dialog/renderer/pick-paths.injectable";
|
||||
import addSyncEntriesInjectable from "../../initializers/add-sync-entries.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../tokens";
|
||||
|
||||
const setupKubernetesClusterCatalogAddMenuListenerInjectable = getInjectable({
|
||||
id: "setup-kubernetes-cluster-catalog-add-menu-listener",
|
||||
instantiate: (di) => ({
|
||||
id: "setup-kubernetes-cluster-catalog-add-menu-listener",
|
||||
run: () => {
|
||||
// NOTE: these have to be here so that they are initialized only after the `runAfter` is ran
|
||||
const navigateToAddCluster = di.inject(navigateToAddClusterInjectable);
|
||||
const addSyncEntries = di.inject(addSyncEntriesInjectable);
|
||||
const kubernetesClusterCategory = di.inject(kubernetesClusterCategoryInjectable);
|
||||
const isWindows = di.inject(isWindowsInjectable);
|
||||
const isLinux = di.inject(isLinuxInjectable);
|
||||
const openPathPickingDialog = di.inject(openPathPickingDialogInjectable);
|
||||
|
||||
kubernetesClusterCategory.on("catalogAddMenu", ctx => {
|
||||
ctx.menuItems.push(
|
||||
{
|
||||
icon: "text_snippet",
|
||||
title: "Add from kubeconfig",
|
||||
onClick: navigateToAddCluster,
|
||||
},
|
||||
);
|
||||
|
||||
if (isWindows || isLinux) {
|
||||
ctx.menuItems.push(
|
||||
{
|
||||
icon: "create_new_folder",
|
||||
title: "Sync kubeconfig folder(s)",
|
||||
defaultAction: true,
|
||||
onClick: () => openPathPickingDialog({
|
||||
message: "Sync folder(s)",
|
||||
buttonLabel: "Sync",
|
||||
properties: ["showHiddenFiles", "multiSelections", "openDirectory"],
|
||||
onPick: addSyncEntries,
|
||||
}),
|
||||
},
|
||||
{
|
||||
icon: "note_add",
|
||||
title: "Sync kubeconfig file(s)",
|
||||
onClick: () => openPathPickingDialog({
|
||||
message: "Sync file(s)",
|
||||
buttonLabel: "Sync",
|
||||
properties: ["showHiddenFiles", "multiSelections", "openFile"],
|
||||
onPick: addSyncEntries,
|
||||
}),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
ctx.menuItems.push(
|
||||
{
|
||||
icon: "create_new_folder",
|
||||
title: "Sync kubeconfig(s)",
|
||||
defaultAction: true,
|
||||
onClick: () => openPathPickingDialog({
|
||||
message: "Sync file(s)",
|
||||
buttonLabel: "Sync",
|
||||
properties: ["showHiddenFiles", "multiSelections", "openFile", "openDirectory"],
|
||||
onPick: addSyncEntries,
|
||||
}),
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupKubernetesClusterCatalogAddMenuListenerInjectable;
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
||||
import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable";
|
||||
import readFileInjectable from "../../../common/fs/read-file.injectable";
|
||||
import { loadConfigFromString } from "../../../common/kube-helpers";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import openDeleteClusterDialogInjectable from "../../components/delete-cluster-dialog/open.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../tokens";
|
||||
|
||||
const setupKubernetesClusterContextMenuOpenInjectable = getInjectable({
|
||||
id: "setup-kubernetes-cluster-context-menu-open",
|
||||
instantiate: (di) => ({
|
||||
id: "setup-kubernetes-cluster-context-menu-open",
|
||||
run: () => {
|
||||
const catalogCategoryRegistry = di.inject(catalogCategoryRegistryInjectable);
|
||||
const openDeleteClusterDialog = di.inject(openDeleteClusterDialogInjectable);
|
||||
const readFile = di.inject(readFileInjectable);
|
||||
const getClusterById = di.inject(getClusterByIdInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
catalogCategoryRegistry
|
||||
.getForGroupKind("entity.k8slens.dev", "KubernetesCluster")
|
||||
?.on("contextMenuOpen", (entity, context) => {
|
||||
if (entity.metadata?.source == "local") {
|
||||
context.menuItems.push({
|
||||
title: "Remove",
|
||||
icon: "delete",
|
||||
onClick: async () => {
|
||||
const clusterId = entity.getId();
|
||||
const cluster = getClusterById(entity.getId());
|
||||
|
||||
if (!cluster) {
|
||||
return logger.warn("[KUBERNETES-CLUSTER]: cannot delete cluster, does not exist in store", { clusterId });
|
||||
}
|
||||
|
||||
const result = loadConfigFromString(await readFile(cluster.kubeConfigPath));
|
||||
|
||||
if (result.error) {
|
||||
logger.error("[KUBERNETES-CLUSTER]: failed to parse kubeconfig file", result.error);
|
||||
} else {
|
||||
openDeleteClusterDialog({ cluster, config: result.config });
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupKubernetesClusterContextMenuOpenInjectable;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import isMacInjectable from "../../../common/vars/is-mac.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../tokens";
|
||||
|
||||
const setupRootMacClassnameInjectable = getInjectable({
|
||||
id: "setup-root-mac-classname",
|
||||
instantiate: (di) => ({
|
||||
id: "setup-root-mac-classname",
|
||||
run: () => {
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
const rootElem = document.getElementById("app");
|
||||
|
||||
rootElem?.classList.toggle("is-mac", isMac);
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupRootMacClassnameInjectable;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import initializeSentryReportingWithInjectable from "../../../common/error-reporting/initialize-sentry-reporting.injectable";
|
||||
import { beforeMainFrameStartsInjectionToken } from "../tokens";
|
||||
import { init } from "@sentry/electron/renderer";
|
||||
|
||||
const setupSentryInjectable = getInjectable({
|
||||
id: "setup-sentry",
|
||||
instantiate: (di) => ({
|
||||
id: "setup-sentry",
|
||||
run: () => {
|
||||
const initializeSentryReportingWith = di.inject(initializeSentryReportingWithInjectable);
|
||||
|
||||
initializeSentryReportingWith(init);
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeMainFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupSentryInjectable;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import React from "react";
|
||||
import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable";
|
||||
import { WeblinkAddCommand } from "../../components/catalog-entities/weblink-add-command";
|
||||
import commandOverlayInjectable from "../../components/command-palette/command-overlay.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../tokens";
|
||||
|
||||
const setupWeblickContextMenuOpenInjectable = getInjectable({
|
||||
id: "setup-weblick-context-menu-open",
|
||||
instantiate: (di) => ({
|
||||
id: "setup-weblick-context-menu-open",
|
||||
run: () => {
|
||||
const catalogCategoryRegistry = di.inject(catalogCategoryRegistryInjectable);
|
||||
const commandOverlay = di.inject(commandOverlayInjectable);
|
||||
|
||||
catalogCategoryRegistry
|
||||
.getForGroupKind("entity.k8slens.dev", "WebLink")
|
||||
?.on("catalogAddMenu", ctx => {
|
||||
ctx.menuItems.push({
|
||||
title: "Add web link",
|
||||
icon: "public",
|
||||
onClick: () => commandOverlay.open(<WeblinkAddCommand />),
|
||||
});
|
||||
});
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupWeblickContextMenuOpenInjectable;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { Runnable } from "../../common/runnable/run-many-for";
|
||||
|
||||
// NOTE: these are run before any other token, mostly to set up things that all other runnables need
|
||||
export const beforeFrameStartsFirstInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "even-before-frame-starts",
|
||||
});
|
||||
|
||||
// NOTE: these are only run when process.isMainFrame === true
|
||||
export const beforeMainFrameStartsInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "even-before-main-frame-starts",
|
||||
});
|
||||
|
||||
// NOTE: these are only run when process.isMainFrame === false
|
||||
export const beforeClusterFrameStartsInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "even-before-cluster-frame-starts",
|
||||
});
|
||||
|
||||
export const beforeFrameStartsInjectionToken = getInjectionToken<Runnable>({
|
||||
id: "before-frame-starts",
|
||||
});
|
||||
|
||||
@@ -13,132 +13,41 @@ import * as ReactRouter from "react-router";
|
||||
import * as ReactRouterDom from "react-router-dom";
|
||||
import * as LensExtensionsCommonApi from "../extensions/common-api";
|
||||
import * as LensExtensionsRendererApi from "../extensions/renderer-api";
|
||||
import { delay } from "../common/utils";
|
||||
import { isMac, isDevelopment } from "../common/vars";
|
||||
import { DefaultProps } from "./mui-base-theme";
|
||||
import configurePackages from "../common/configure-packages";
|
||||
import * as initializers from "./initializers";
|
||||
import logger from "../common/logger";
|
||||
import { WeblinkStore } from "../common/weblink-store";
|
||||
import { registerCustomThemes } from "./components/monaco-editor";
|
||||
import { getDi } from "./getDi";
|
||||
import { DiContextProvider } from "@ogre-tools/injectable-react";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import extensionLoaderInjectable from "../extensions/extension-loader/extension-loader.injectable";
|
||||
import extensionDiscoveryInjectable from "../extensions/extension-discovery/extension-discovery.injectable";
|
||||
import extensionInstallationStateStoreInjectable from "../extensions/extension-installation-state-store/extension-installation-state-store.injectable";
|
||||
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
|
||||
import initRootFrameInjectable from "./frames/root-frame/init-root-frame/init-root-frame.injectable";
|
||||
import initClusterFrameInjectable from "./frames/cluster-frame/init-cluster-frame/init-cluster-frame.injectable";
|
||||
import commandOverlayInjectable from "./components/command-palette/command-overlay.injectable";
|
||||
import { Router } from "react-router";
|
||||
import historyInjectable from "./navigation/history.injectable";
|
||||
import themeStoreInjectable from "./themes/store.injectable";
|
||||
import navigateToAddClusterInjectable from "../common/front-end-routing/routes/add-cluster/navigate-to-add-cluster.injectable";
|
||||
import addSyncEntriesInjectable from "./initializers/add-sync-entries.injectable";
|
||||
import hotbarStoreInjectable from "../common/hotbars/store.injectable";
|
||||
import { bindEvents } from "./navigation/events";
|
||||
import openDeleteClusterDialogInjectable from "./components/delete-cluster-dialog/open.injectable";
|
||||
import { init } from "@sentry/electron/renderer";
|
||||
import kubernetesClusterCategoryInjectable from "../common/catalog/categories/kubernetes-cluster.injectable";
|
||||
import autoRegistrationInjectable from "../common/k8s-api/api-manager/auto-registration.injectable";
|
||||
import assert from "assert";
|
||||
import startFrameInjectable from "./start-frame/start-frame.injectable";
|
||||
import initializeSentryReportingWithInjectable from "../common/error-reporting/initialize-sentry-reporting.injectable";
|
||||
|
||||
configurePackages(); // global packages
|
||||
registerCustomThemes(); // monaco editor themes
|
||||
|
||||
/**
|
||||
* If this is a development build, wait a second to attach
|
||||
* Chrome Debugger to renderer process
|
||||
* https://stackoverflow.com/questions/52844870/debugging-electron-renderer-process-with-vscode
|
||||
*/
|
||||
async function attachChromeDebugger() {
|
||||
if (isDevelopment) {
|
||||
await delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
export async function bootstrap(di: DiContainer) {
|
||||
const initializeSentryReportingWith = di.inject(initializeSentryReportingWithInjectable);
|
||||
|
||||
if (process.isMainFrame) {
|
||||
initializeSentryReportingWith(init);
|
||||
}
|
||||
|
||||
const startFrame = di.inject(startFrameInjectable);
|
||||
|
||||
await startFrame();
|
||||
|
||||
// TODO: Consolidate import time side-effect to setup time
|
||||
bindEvents();
|
||||
|
||||
const rootElem = document.getElementById("app");
|
||||
const logPrefix = `[BOOTSTRAP-${process.isMainFrame ? "ROOT" : "CLUSTER"}-FRAME]:`;
|
||||
|
||||
assert(rootElem, "#app MUST exist");
|
||||
|
||||
|
||||
/**
|
||||
* This is injected here to initialize it for the side effect.
|
||||
*
|
||||
* The side effect CANNOT be within `apiManagerInjectable` itself since that causes circular
|
||||
* dependencies with the current need for legacy di use.
|
||||
*
|
||||
* This also MUST be done before anything else so that it can start listening for the events for
|
||||
* auto initialization.
|
||||
*/
|
||||
di.inject(autoRegistrationInjectable);
|
||||
|
||||
await attachChromeDebugger();
|
||||
rootElem.classList.toggle("is-mac", isMac);
|
||||
|
||||
logger.info(`${logPrefix} initializing CatalogCategoryRegistryEntries`);
|
||||
initializers.initCatalogCategoryRegistryEntries({
|
||||
navigateToAddCluster: di.inject(navigateToAddClusterInjectable),
|
||||
addSyncEntries: di.inject(addSyncEntriesInjectable),
|
||||
kubernetesClusterCategory: di.inject(kubernetesClusterCategoryInjectable),
|
||||
});
|
||||
|
||||
logger.info(`${logPrefix} initializing Catalog`);
|
||||
initializers.initCatalog({
|
||||
openCommandDialog: di.inject(commandOverlayInjectable).open,
|
||||
openDeleteClusterDialog: di.inject(openDeleteClusterDialogInjectable),
|
||||
});
|
||||
|
||||
const extensionLoader = di.inject(extensionLoaderInjectable);
|
||||
|
||||
logger.info(`${logPrefix} initializing IpcRendererListeners`);
|
||||
initializers.initIpcRendererListeners(extensionLoader);
|
||||
|
||||
extensionLoader.init();
|
||||
|
||||
const extensionDiscovery = di.inject(extensionDiscoveryInjectable);
|
||||
|
||||
extensionDiscovery.init();
|
||||
|
||||
// ClusterStore depends on: UserStore
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
|
||||
await clusterStore.loadInitialOnRenderer();
|
||||
|
||||
// HotbarStore depends on: ClusterStore
|
||||
di.inject(hotbarStoreInjectable).load();
|
||||
|
||||
// ThemeStore depends on: UserStore
|
||||
// TODO: Remove temporal dependencies
|
||||
di.inject(themeStoreInjectable);
|
||||
|
||||
WeblinkStore.createInstance();
|
||||
|
||||
const extensionInstallationStateStore = di.inject(extensionInstallationStateStoreInjectable);
|
||||
|
||||
extensionInstallationStateStore.bindIpcListeners();
|
||||
|
||||
// Register additional store listeners
|
||||
clusterStore.registerIpcListener();
|
||||
|
||||
let App;
|
||||
let initializeApp;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import type { CategoryColumns, GetCategoryColumnsParams } from "../columns/get.i
|
||||
import getCategoryColumnsInjectable from "../columns/get.injectable";
|
||||
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
||||
import extensionInjectable from "../../../../extensions/extension-loader/extension/extension.injectable";
|
||||
import currentlyInClusterFrameInjectable from "../../../routes/currently-in-cluster-frame.injectable";
|
||||
|
||||
class TestCategory extends CatalogCategory {
|
||||
apiVersion = "catalog.k8slens.dev/v1alpha1";
|
||||
@@ -46,6 +47,8 @@ describe("Custom Category Columns", () => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(hotbarStoreInjectable, () => ({}));
|
||||
di.override(currentlyInClusterFrameInjectable, () => false);
|
||||
|
||||
getCategoryColumns = di.inject(getCategoryColumnsInjectable);
|
||||
});
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ import broadcastMessageInjectable from "../../../common/ipc/broadcast-message.in
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import { flushPromises } from "../../../common/test-utils/flush-promises";
|
||||
import userStoreInjectable from "../../../common/user-store/user-store.injectable";
|
||||
import releaseChannelInjectable from "../../../common/vars/release-channel.injectable";
|
||||
import defaultUpdateChannelInjectable from "../../../features/application-update/common/selected-update-channel/default-update-channel.injectable";
|
||||
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
|
||||
|
||||
class MockCatalogEntity extends CatalogEntity {
|
||||
public apiVersion = "api";
|
||||
@@ -61,11 +65,11 @@ describe("<Catalog />", () => {
|
||||
let catalogEntityItem: MockCatalogEntity;
|
||||
let render: DiRender;
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
|
||||
di.override(currentlyInClusterFrameInjectable, () => false);
|
||||
di.override(broadcastMessageInjectable, () => async () => {});
|
||||
|
||||
di.permitSideEffects(getConfigurationFileModelInjectable);
|
||||
@@ -82,6 +86,13 @@ describe("<Catalog />", () => {
|
||||
Object.assign(catalogEntityStore, {
|
||||
selectedItem: computed(() => catalogEntityItem),
|
||||
});
|
||||
|
||||
di.override(releaseChannelInjectable, () => ({
|
||||
get: () => "latest" as const,
|
||||
init: async () => {},
|
||||
}));
|
||||
await di.inject(defaultUpdateChannelInjectable).init();
|
||||
di.inject(userStoreInjectable).load();
|
||||
});
|
||||
|
||||
describe("can use catalogEntityRegistry.addOnBeforeRun to add hooks for catalog entities", () => {
|
||||
|
||||
@@ -27,7 +27,7 @@ import type { PageParam } from "../../navigation";
|
||||
import type { ToggleKubeDetailsPane } from "../kube-detail-params/toggle-details.injectable";
|
||||
import kubeSelectedUrlParamInjectable from "../kube-detail-params/kube-selected-url.injectable";
|
||||
import toggleKubeDetailsPaneInjectable from "../kube-detail-params/toggle-details.injectable";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import activeThemeInjectable from "../../themes/active.injectable";
|
||||
|
||||
export interface ClusterIssuesProps {
|
||||
|
||||
@@ -16,7 +16,7 @@ import type { PieChartData } from "../chart";
|
||||
import { PieChart } from "../chart";
|
||||
import { ClusterNoMetrics } from "./cluster-no-metrics";
|
||||
import { bytesToUnits, cssNames } from "../../utils";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { getMetricLastPoints } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import clusterOverviewStoreInjectable from "./cluster-overview-store/cluster-overview-store.injectable";
|
||||
|
||||
@@ -23,12 +23,13 @@ import installExtensionFromInputInjectable from "../install-extension-from-input
|
||||
import type { ExtensionInstallationStateStore } from "../../../../extensions/extension-installation-state-store/extension-installation-state-store";
|
||||
import extensionInstallationStateStoreInjectable from "../../../../extensions/extension-installation-state-store/extension-installation-state-store.injectable";
|
||||
import { observable, when } from "mobx";
|
||||
import type { DeleteFile } from "../../../../common/fs/delete-file.injectable";
|
||||
import deleteFileInjectable from "../../../../common/fs/delete-file.injectable";
|
||||
import type { RemovePath } from "../../../../common/fs/remove.injectable";
|
||||
import removePathInjectable from "../../../../common/fs/remove.injectable";
|
||||
import type { DownloadJson } from "../../../../common/fetch/download-json.injectable";
|
||||
import type { DownloadBinary } from "../../../../common/fetch/download-binary.injectable";
|
||||
import downloadJsonInjectable from "../../../../common/fetch/download-json.injectable";
|
||||
import downloadBinaryInjectable from "../../../../common/fetch/download-binary.injectable";
|
||||
import currentlyInClusterFrameInjectable from "../../../routes/currently-in-cluster-frame.injectable";
|
||||
|
||||
describe("Extensions", () => {
|
||||
let extensionLoader: ExtensionLoader;
|
||||
@@ -36,7 +37,7 @@ describe("Extensions", () => {
|
||||
let installExtensionFromInput: jest.MockedFunction<InstallExtensionFromInput>;
|
||||
let extensionInstallationStateStore: ExtensionInstallationStateStore;
|
||||
let render: DiRender;
|
||||
let deleteFileMock: jest.MockedFunction<DeleteFile>;
|
||||
let deleteFileMock: jest.MockedFunction<RemovePath>;
|
||||
let downloadJson: jest.MockedFunction<DownloadJson>;
|
||||
let downloadBinary: jest.MockedFunction<DownloadBinary>;
|
||||
|
||||
@@ -45,6 +46,7 @@ describe("Extensions", () => {
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
di.override(directoryForDownloadsInjectable, () => "some-directory-for-downloads");
|
||||
di.override(currentlyInClusterFrameInjectable, () => false);
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
@@ -52,7 +54,7 @@ describe("Extensions", () => {
|
||||
di.override(installExtensionFromInputInjectable, () => installExtensionFromInput);
|
||||
|
||||
deleteFileMock = jest.fn();
|
||||
di.override(deleteFileInjectable, () => deleteFileMock);
|
||||
di.override(removePathInjectable, () => deleteFileMock);
|
||||
|
||||
downloadJson = jest.fn().mockImplementation((url) => { throw new Error(`Unexpected call to downloadJson for url=${url}`); });
|
||||
di.override(downloadJsonInjectable, () => downloadJson);
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import {
|
||||
getInjectable,
|
||||
} from "@ogre-tools/injectable";
|
||||
import { UserStore } from "../../../../common/user-store";
|
||||
import { getBaseRegistryUrl } from "./get-base-registry-url";
|
||||
|
||||
const getBaseRegistryUrlInjectable = getInjectable({
|
||||
id: "get-base-registry-url",
|
||||
|
||||
instantiate: () => getBaseRegistryUrl({
|
||||
// TODO: use injection
|
||||
getRegistryUrlPreference: () => UserStore.getInstance().extensionRegistryUrl,
|
||||
}),
|
||||
});
|
||||
|
||||
export default getBaseRegistryUrlInjectable;
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import React from "react";
|
||||
import execFileInjectable from "../../../../common/fs/exec-file.injectable";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import { defaultExtensionRegistryUrl } from "../../../../common/user-store/preferences-helpers";
|
||||
import userStoreInjectable from "../../../../common/user-store/user-store.injectable";
|
||||
import showErrorNotificationInjectable from "../../notifications/show-error-notification.injectable";
|
||||
|
||||
const getBaseRegistryUrlInjectable = getInjectable({
|
||||
id: "get-base-registry-url",
|
||||
|
||||
instantiate: (di) => {
|
||||
const { extensionRegistryUrl } = di.inject(userStoreInjectable);
|
||||
const showErrorNotification = di.inject(showErrorNotificationInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const execFile = di.inject(execFileInjectable);
|
||||
|
||||
return async () => {
|
||||
switch (extensionRegistryUrl.location) {
|
||||
case "custom":
|
||||
return extensionRegistryUrl.customUrl;
|
||||
|
||||
case "npmrc": {
|
||||
const filteredEnv = Object.fromEntries(
|
||||
Object.entries(process.env)
|
||||
.filter(([key]) => !key.startsWith("npm")),
|
||||
);
|
||||
const result = await execFile("npm", ["config", "get", "registry"], { env: filteredEnv });
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response.trim();
|
||||
}
|
||||
|
||||
showErrorNotification((
|
||||
<p>
|
||||
Failed to get configured registry from
|
||||
<code>.npmrc</code>
|
||||
. Falling back to default registry.
|
||||
</p>
|
||||
));
|
||||
logger.warn("[EXTENSIONS]: failed to get configured registry from .npmrc", result.error);
|
||||
}
|
||||
|
||||
// fallthrough
|
||||
default:
|
||||
case "default":
|
||||
return defaultExtensionRegistryUrl;
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default getBaseRegistryUrlInjectable;
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import type { ExtensionRegistry } from "../../../../common/user-store/preferences-helpers";
|
||||
import { defaultExtensionRegistryUrl } from "../../../../common/user-store/preferences-helpers";
|
||||
import { promiseExecFile } from "../../../utils";
|
||||
import { Notifications } from "../../notifications";
|
||||
|
||||
interface Dependencies {
|
||||
getRegistryUrlPreference: () => ExtensionRegistry;
|
||||
}
|
||||
|
||||
export const getBaseRegistryUrl = ({ getRegistryUrlPreference }: Dependencies) => async () => {
|
||||
const extensionRegistryUrl = getRegistryUrlPreference();
|
||||
|
||||
switch (extensionRegistryUrl.location) {
|
||||
case "custom":
|
||||
return extensionRegistryUrl.customUrl;
|
||||
|
||||
case "npmrc": {
|
||||
try {
|
||||
const filteredEnv = Object.fromEntries(
|
||||
Object.entries(process.env)
|
||||
.filter(([key]) => !key.startsWith("npm")),
|
||||
);
|
||||
const { stdout } = await promiseExecFile("npm", ["config", "get", "registry"], { env: filteredEnv });
|
||||
|
||||
return stdout.trim();
|
||||
} catch (error) {
|
||||
Notifications.error((
|
||||
<p>
|
||||
Failed to get configured registry from
|
||||
<code>.npmrc</code>
|
||||
. Falling back to default registry.
|
||||
</p>
|
||||
));
|
||||
console.warn("[EXTENSIONS]: failed to get configured registry from .npmrc", error);
|
||||
}
|
||||
}
|
||||
|
||||
// fallthrough
|
||||
default:
|
||||
case "default":
|
||||
return defaultExtensionRegistryUrl;
|
||||
}
|
||||
};
|
||||
@@ -3,37 +3,30 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { requestOpenFilePickingDialog } from "../../ipc";
|
||||
import { supportedExtensionFormats } from "./supported-extension-formats";
|
||||
import attemptInstallsInjectable from "./attempt-installs.injectable";
|
||||
import directoryForDownloadsInjectable from "../../../common/app-paths/directory-for-downloads/directory-for-downloads.injectable";
|
||||
import openPathPickingDialogInjectable from "../../../features/path-picking-dialog/renderer/pick-paths.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
attemptInstalls: (filePaths: string[]) => Promise<void>;
|
||||
directoryForDownloads: string;
|
||||
}
|
||||
|
||||
const installFromSelectFileDialog = ({ attemptInstalls, directoryForDownloads }: Dependencies) => async () => {
|
||||
const { canceled, filePaths } = await requestOpenFilePickingDialog({
|
||||
defaultPath: directoryForDownloads,
|
||||
properties: ["openFile", "multiSelections"],
|
||||
message: `Select extensions to install (formats: ${supportedExtensionFormats.join(", ")}), `,
|
||||
buttonLabel: "Use configuration",
|
||||
filters: [{ name: "tarball", extensions: supportedExtensionFormats }],
|
||||
});
|
||||
|
||||
if (!canceled) {
|
||||
await attemptInstalls(filePaths);
|
||||
}
|
||||
};
|
||||
export type InstallFromSelectFileDialog = () => Promise<void>;
|
||||
|
||||
const installFromSelectFileDialogInjectable = getInjectable({
|
||||
id: "install-from-select-file-dialog",
|
||||
|
||||
instantiate: (di) => installFromSelectFileDialog({
|
||||
attemptInstalls: di.inject(attemptInstallsInjectable),
|
||||
directoryForDownloads: di.inject(directoryForDownloadsInjectable),
|
||||
}),
|
||||
instantiate: (di): InstallFromSelectFileDialog => {
|
||||
const attemptInstalls = di.inject(attemptInstallsInjectable);
|
||||
const directoryForDownloads = di.inject(directoryForDownloadsInjectable);
|
||||
const openPathPickingDialog = di.inject(openPathPickingDialogInjectable);
|
||||
|
||||
return () => openPathPickingDialog({
|
||||
defaultPath: directoryForDownloads,
|
||||
properties: ["openFile", "multiSelections"],
|
||||
message: `Select extensions to install (formats: ${supportedExtensionFormats.join(", ")}), `,
|
||||
buttonLabel: "Use configuration",
|
||||
filters: [{ name: "tarball", extensions: supportedExtensionFormats }],
|
||||
onPick: attemptInstalls,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default installFromSelectFileDialogInjectable;
|
||||
+1
-1
@@ -8,7 +8,7 @@ import { runInAction, action, observable, computed } from "mobx";
|
||||
import type { TargetHelmRelease } from "../target-helm-release.injectable";
|
||||
import type { RequestDetailedHelmRelease, DetailedHelmRelease } from "./request-detailed-helm-release.injectable";
|
||||
import requestDetailedHelmReleaseInjectable from "./request-detailed-helm-release.injectable";
|
||||
import type { LensTheme } from "../../../../themes/store";
|
||||
import type { LensTheme } from "../../../../themes/lens-theme";
|
||||
import type { RequestHelmReleaseConfiguration } from "../../../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||
import requestHelmReleaseConfigurationInjectable from "../../../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ResourceMetricsContext } from "../resource-metrics";
|
||||
import { observer } from "mobx-react";
|
||||
import { mapValues } from "lodash";
|
||||
import { type MetricsTab, metricTabOptions } from "../chart/options";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import activeThemeInjectable from "../../themes/active.injectable";
|
||||
|
||||
@@ -10,7 +10,7 @@ import { BarChart, memoryOptions } from "../chart";
|
||||
import { isMetricsEmpty, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
import { NoMetrics } from "../resource-metrics/no-metrics";
|
||||
import { ResourceMetricsContext } from "../resource-metrics";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import activeThemeInjectable from "../../themes/active.injectable";
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ import type { DiRender } from "../../../test-utils/renderFor";
|
||||
import { renderFor } from "../../../test-utils/renderFor";
|
||||
import clusterRoleStoreInjectable from "../../+cluster-roles/store.injectable";
|
||||
import storesAndApisCanBeCreatedInjectable from "../../../../stores-apis-can-be-created.injectable";
|
||||
import directoryForUserDataInjectable from "../../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
|
||||
describe("ClusterRoleBindingDialog tests", () => {
|
||||
let render: DiRender;
|
||||
@@ -20,6 +21,7 @@ describe("ClusterRoleBindingDialog tests", () => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(storesAndApisCanBeCreatedInjectable, () => true);
|
||||
di.override(directoryForUserDataInjectable, () => "/some-path-for-user-data");
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import rendererExtensionsInjectable from "../../../../extensions/renderer-extensions.injectable";
|
||||
import { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
||||
import type { WelcomeBannerRegistration } from "../welcome-banner-items/welcome-banner-registration";
|
||||
import currentlyInClusterFrameInjectable from "../../../routes/currently-in-cluster-frame.injectable";
|
||||
|
||||
jest.mock("electron", () => ({
|
||||
ipcRenderer: {
|
||||
@@ -32,6 +33,9 @@ describe("<Welcome/>", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(currentlyInClusterFrameInjectable, () => false);
|
||||
|
||||
render = renderFor(di);
|
||||
welcomeBannersStub = [];
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { observer } from "mobx-react";
|
||||
import type { PieChartData } from "../chart";
|
||||
import { PieChart } from "../chart";
|
||||
import { object } from "../../utils";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { PascalCase } from "type-fest";
|
||||
import type { IComputedValue } from "mobx";
|
||||
|
||||
@@ -10,7 +10,7 @@ import { BarChart } from "../chart";
|
||||
import { isMetricsEmpty, normalizeMetrics } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
import { NoMetrics } from "../resource-metrics/no-metrics";
|
||||
import { ResourceMetricsContext } from "../resource-metrics";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { mapValues } from "lodash";
|
||||
import { type MetricsTab, metricTabOptions } from "../chart/options";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
@tailwind utilities;
|
||||
|
||||
@import "./flexbox";
|
||||
@import "../themes/theme-vars";
|
||||
@import "./fonts";
|
||||
|
||||
:root {
|
||||
|
||||
@@ -7,13 +7,15 @@ import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Input } from "../input";
|
||||
import { isUrl } from "../input/input_validators";
|
||||
import { WeblinkStore } from "../../../common/weblink-store";
|
||||
import type { WeblinkStore } from "../../../common/weblinks-store/weblink-store";
|
||||
import { computed, makeObservable, observable } from "mobx";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import commandOverlayInjectable from "../command-palette/command-overlay.injectable";
|
||||
import weblinkStoreInjectable from "../../../common/weblinks-store/weblink-store.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
closeCommandOverlay: () => void;
|
||||
weblinkStore: WeblinkStore;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +42,7 @@ class NonInjectedWeblinkAddCommand extends React.Component<Dependencies> {
|
||||
}
|
||||
|
||||
onSubmit(name: string) {
|
||||
WeblinkStore.getInstance().add({
|
||||
this.props.weblinkStore.add({
|
||||
name: name || this.url,
|
||||
url: this.url,
|
||||
});
|
||||
@@ -64,7 +66,7 @@ class NonInjectedWeblinkAddCommand extends React.Component<Dependencies> {
|
||||
value={this.url}
|
||||
onChange={(v) => this.onChangeUrl(v)}
|
||||
onSubmit={(v) => this.onSubmitUrl(v)}
|
||||
showValidationLine={true}
|
||||
showValidationLine={true}
|
||||
/>
|
||||
{ this.nameHidden && (
|
||||
<small className="hint">
|
||||
@@ -93,7 +95,8 @@ class NonInjectedWeblinkAddCommand extends React.Component<Dependencies> {
|
||||
|
||||
export const WeblinkAddCommand = withInjectables<Dependencies>(NonInjectedWeblinkAddCommand, {
|
||||
getProps: (di, props) => ({
|
||||
closeCommandOverlay: di.inject(commandOverlayInjectable).close,
|
||||
...props,
|
||||
closeCommandOverlay: di.inject(commandOverlayInjectable).close,
|
||||
weblinkStore: di.inject(weblinkStoreInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import type { ChartProps } from "./chart";
|
||||
import { Chart, ChartKind } from "./chart";
|
||||
import { bytesToUnits, cssNames, isObject } from "../../utils";
|
||||
import { ZebraStripesPlugin } from "./zebra-stripes.plugin";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { NoMetrics } from "../resource-metrics/no-metrics";
|
||||
import assert from "assert";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
|
||||
@@ -11,7 +11,7 @@ import ChartJS from "chart.js";
|
||||
import type { ChartProps } from "./chart";
|
||||
import { Chart } from "./chart";
|
||||
import { cssNames } from "../../utils";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import activeThemeInjectable from "../../themes/active.injectable";
|
||||
|
||||
@@ -37,11 +37,18 @@ export class ClusterFrameHandler {
|
||||
@action
|
||||
public initView(clusterId: ClusterId) {
|
||||
const cluster = this.dependencies.getClusterById(clusterId);
|
||||
|
||||
if (!cluster) {
|
||||
this.dependencies.logger.warn(`[LENS-VIEW]: not initializing view; unknown clusterId="${clusterId}"`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const parentElem = document.getElementById("lens-views");
|
||||
|
||||
assert(parentElem, "DOM with #lens-views must be present");
|
||||
|
||||
if (!cluster || this.views.has(clusterId)) {
|
||||
if (this.views.has(clusterId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { ClusterStatus } from "./cluster-status";
|
||||
import type { ClusterFrameHandler } from "./cluster-frame-handler";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||
import { requestClusterActivation } from "../../ipc";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { NavigateToCatalog } from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||
@@ -20,18 +19,19 @@ import clusterViewRouteParametersInjectable from "./cluster-view-route-parameter
|
||||
import clusterFrameHandlerInjectable from "./cluster-frame-handler.injectable";
|
||||
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||
import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable";
|
||||
import type { GetClusterById } from "../../../common/cluster-store/get-by-id.injectable";
|
||||
import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
clusterId: IComputedValue<string>;
|
||||
clusterFrames: ClusterFrameHandler;
|
||||
navigateToCatalog: NavigateToCatalog;
|
||||
entityRegistry: CatalogEntityRegistry;
|
||||
getClusterById: GetClusterById;
|
||||
}
|
||||
|
||||
@observer
|
||||
class NonInjectedClusterView extends React.Component<Dependencies> {
|
||||
private readonly store = ClusterStore.getInstance();
|
||||
|
||||
constructor(props: Dependencies) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
@@ -42,7 +42,7 @@ class NonInjectedClusterView extends React.Component<Dependencies> {
|
||||
}
|
||||
|
||||
@computed get cluster(): Cluster | undefined {
|
||||
return this.store.getById(this.clusterId);
|
||||
return this.props.getClusterById(this.clusterId);
|
||||
}
|
||||
|
||||
private readonly isViewLoaded = computed(() => this.props.clusterFrames.hasLoadedView(this.clusterId), {
|
||||
@@ -110,10 +110,11 @@ class NonInjectedClusterView extends React.Component<Dependencies> {
|
||||
|
||||
export const ClusterView = withInjectables<Dependencies>(NonInjectedClusterView, {
|
||||
getProps: (di) => ({
|
||||
clusterId: di.inject(clusterViewRouteParametersInjectable).clusterId,
|
||||
...di.inject(clusterViewRouteParametersInjectable),
|
||||
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
||||
clusterFrames: di.inject(clusterFrameHandlerInjectable),
|
||||
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||
getClusterById: di.inject(getClusterByIdInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import type { DiRender } from "../../test-utils/renderFor";
|
||||
import { renderFor } from "../../test-utils/renderFor";
|
||||
import showErrorNotificationInjectable from "../../notifications/show-error-notification.injectable";
|
||||
import statInjectable from "../../../../common/fs/stat/stat.injectable";
|
||||
import statInjectable from "../../../../common/fs/stat.injectable";
|
||||
|
||||
describe("ClusterLocalTerminalSettings", () => {
|
||||
let render: DiRender;
|
||||
|
||||
@@ -10,7 +10,6 @@ import { Input } from "../input";
|
||||
import { SubTitle } from "../layout/sub-title";
|
||||
import type { ShowNotification } from "../notifications";
|
||||
import { Icon } from "../icon";
|
||||
import { PathPicker } from "../path-picker";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable";
|
||||
import type { ValidateDirectory } from "../../../common/fs/validate-directory.injectable";
|
||||
@@ -19,6 +18,8 @@ import type { ResolveTilde } from "../../../common/path/resolve-tilde.injectable
|
||||
import resolveTildeInjectable from "../../../common/path/resolve-tilde.injectable";
|
||||
import Gutter from "../gutter/gutter";
|
||||
import isWindowsInjectable from "../../../common/vars/is-windows.injectable";
|
||||
import type { OpenPathPickingDialog } from "../../../features/path-picking-dialog/renderer/pick-paths.injectable";
|
||||
import openPathPickingDialogInjectable from "../../../features/path-picking-dialog/renderer/pick-paths.injectable";
|
||||
|
||||
export interface ClusterLocalTerminalSettingProps {
|
||||
cluster: Cluster;
|
||||
@@ -27,6 +28,7 @@ interface Dependencies {
|
||||
showErrorNotification: ShowNotification;
|
||||
validateDirectory: ValidateDirectory;
|
||||
resolveTilde: ResolveTilde;
|
||||
openPathPickingDialog: OpenPathPickingDialog;
|
||||
isWindows: boolean;
|
||||
}
|
||||
|
||||
@@ -36,6 +38,7 @@ const NonInjectedClusterLocalTerminalSetting = observer(({
|
||||
validateDirectory,
|
||||
resolveTilde,
|
||||
isWindows,
|
||||
openPathPickingDialog,
|
||||
}: Dependencies & ClusterLocalTerminalSettingProps) => {
|
||||
if (!cluster) {
|
||||
return null;
|
||||
@@ -95,8 +98,8 @@ const NonInjectedClusterLocalTerminalSetting = observer(({
|
||||
};
|
||||
|
||||
const openFilePicker = () => {
|
||||
PathPicker.pick({
|
||||
label: "Choose Working Directory",
|
||||
openPathPickingDialog({
|
||||
message: "Choose Working Directory",
|
||||
buttonLabel: "Pick",
|
||||
properties: ["openDirectory", "showHiddenFiles"],
|
||||
onPick: ([directory]) => setAndCommitDirectory(directory),
|
||||
@@ -168,5 +171,6 @@ export const ClusterLocalTerminalSetting = withInjectables<Dependencies, Cluster
|
||||
validateDirectory: di.inject(validateDirectoryInjectable),
|
||||
resolveTilde: di.inject(resolveTildeInjectable),
|
||||
isWindows: di.inject(isWindowsInjectable),
|
||||
openPathPickingDialog: di.inject(openPathPickingDialogInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -15,13 +15,15 @@ import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import moment from "moment-timezone";
|
||||
import type { Align, ListOnScrollProps } from "react-window";
|
||||
import { SearchStore } from "../../../search-store/search-store";
|
||||
import { UserStore } from "../../../../common/user-store";
|
||||
import type { UserStore } from "../../../../common/user-store";
|
||||
import { array, autoBind, cssNames } from "../../../utils";
|
||||
import type { VirtualListRef } from "../../virtual-list";
|
||||
import { VirtualList } from "../../virtual-list";
|
||||
import { ToBottom } from "./to-bottom";
|
||||
import type { LogTabViewModel } from "../logs/logs-view-model";
|
||||
import { Spinner } from "../../spinner";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import userStoreInjectable from "../../../../common/user-store/user-store.injectable";
|
||||
|
||||
export interface LogListProps {
|
||||
model: LogTabViewModel;
|
||||
@@ -33,8 +35,12 @@ export interface LogListRef {
|
||||
scrollToItem: (index: number, align: Align) => void;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
}
|
||||
|
||||
@observer
|
||||
class NonForwardedLogList extends React.Component<LogListProps & { innerRef: ForwardedRef<LogListRef> }> {
|
||||
class NonForwardedLogList extends React.Component<Dependencies & LogListProps & { innerRef: ForwardedRef<LogListRef> }> {
|
||||
@observable isJumpButtonVisible = false;
|
||||
@observable isLastLineVisible = true;
|
||||
|
||||
@@ -122,7 +128,7 @@ class NonForwardedLogList extends React.Component<LogListProps & { innerRef: For
|
||||
|
||||
return this.props.model.timestampSplitLogs
|
||||
.get()
|
||||
.map(([logTimestamp, log]) => (`${logTimestamp && moment.tz(logTimestamp, UserStore.getInstance().localeTimezone).format()}${log}`));
|
||||
.map(([logTimestamp, log]) => (`${logTimestamp && moment.tz(logTimestamp, this.props.userStore.localeTimezone).format()}${log}`));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,6 +279,13 @@ class NonForwardedLogList extends React.Component<LogListProps & { innerRef: For
|
||||
}
|
||||
}
|
||||
|
||||
const InjectedNonForwardedLogList = withInjectables<Dependencies, LogListProps & { innerRef: ForwardedRef<LogListRef> }>(NonForwardedLogList, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export const LogList = React.forwardRef<LogListRef, LogListProps>((props, ref) => (
|
||||
<NonForwardedLogList {...props} innerRef={ref} />
|
||||
<InjectedNonForwardedLogList {...props} innerRef={ref} />
|
||||
));
|
||||
@@ -10,9 +10,9 @@ import type { TerminalApi } from "../../../api/terminal-api";
|
||||
import terminalSpawningPoolInjectable from "./terminal-spawning-pool.injectable";
|
||||
import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable";
|
||||
import terminalCopyOnSelectInjectable from "../../../../common/user-store/terminal-copy-on-select.injectable";
|
||||
import themeStoreInjectable from "../../../themes/store.injectable";
|
||||
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
|
||||
import openLinkInBrowserInjectable from "../../../../common/utils/open-link-in-browser.injectable";
|
||||
import xtermColorThemeInjectable from "../../../themes/terminal-colors.injectable";
|
||||
|
||||
export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal;
|
||||
|
||||
@@ -23,9 +23,9 @@ const createTerminalInjectable = getInjectable({
|
||||
spawningPool: di.inject(terminalSpawningPoolInjectable),
|
||||
terminalConfig: di.inject(terminalConfigInjectable),
|
||||
terminalCopyOnSelect: di.inject(terminalCopyOnSelectInjectable),
|
||||
themeStore: di.inject(themeStoreInjectable),
|
||||
isMac: di.inject(isMacInjectable),
|
||||
openLinkInBrowser: di.inject(openLinkInBrowserInjectable),
|
||||
xtermColorTheme: di.inject(xtermColorThemeInjectable),
|
||||
};
|
||||
|
||||
return (tabId, api) => new Terminal(dependencies, { tabId, api });
|
||||
|
||||
@@ -10,7 +10,6 @@ import { Terminal as XTerm } from "xterm";
|
||||
import { FitAddon } from "xterm-addon-fit";
|
||||
import type { TabId } from "../dock/store";
|
||||
import type { TerminalApi } from "../../../api/terminal-api";
|
||||
import type { ThemeStore } from "../../../themes/store";
|
||||
import { disposer } from "../../../utils";
|
||||
import { once } from "lodash";
|
||||
import { clipboard } from "electron";
|
||||
@@ -25,8 +24,8 @@ export interface TerminalDependencies {
|
||||
readonly spawningPool: HTMLElement;
|
||||
readonly terminalConfig: IComputedValue<TerminalConfig>;
|
||||
readonly terminalCopyOnSelect: IComputedValue<boolean>;
|
||||
readonly themeStore: ThemeStore;
|
||||
readonly isMac: boolean;
|
||||
readonly xtermColorTheme: IComputedValue<Record<string, string>>;
|
||||
openLinkInBrowser: OpenLinkInBrowser;
|
||||
}
|
||||
|
||||
@@ -75,10 +74,6 @@ export class Terminal {
|
||||
return this.dependencies.terminalConfig.get().fontSize;
|
||||
}
|
||||
|
||||
get theme(): Record<string/*paramName*/, string/*color*/> {
|
||||
return this.dependencies.themeStore.xtermColors;
|
||||
}
|
||||
|
||||
constructor(protected readonly dependencies: TerminalDependencies, {
|
||||
tabId,
|
||||
api,
|
||||
@@ -120,9 +115,12 @@ export class Terminal {
|
||||
|
||||
this.disposer.push(
|
||||
this.xterm.registerLinkProvider(linkProvider),
|
||||
reaction(() => this.theme, colors => this.xterm.setOption("theme", colors), {
|
||||
fireImmediately: true,
|
||||
}),
|
||||
reaction(() => this.dependencies.xtermColorTheme.get(),
|
||||
colors => this.xterm.options.theme = colors,
|
||||
{
|
||||
fireImmediately: true,
|
||||
},
|
||||
),
|
||||
reaction(() => this.fontSize, this.setFontSize, { fireImmediately: true }),
|
||||
reaction(() => this.fontFamily, this.setFontFamily, { fireImmediately: true }),
|
||||
() => onDataHandler.dispose(),
|
||||
|
||||
@@ -10,7 +10,7 @@ import { disposeOnUnmount, observer } from "mobx-react";
|
||||
import { cssNames } from "../../../utils";
|
||||
import type { Terminal } from "./terminal";
|
||||
import type { TerminalStore } from "./store";
|
||||
import type { LensTheme } from "../../../themes/store";
|
||||
import type { LensTheme } from "../../../themes/lens-theme";
|
||||
import type { DockTab, DockStore } from "../dock/store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import dockStoreInjectable from "../dock/store.injectable";
|
||||
|
||||
@@ -21,7 +21,7 @@ import { NoItems } from "../no-items";
|
||||
import { Spinner } from "../spinner";
|
||||
import type { ItemObject } from "../../../common/item.store";
|
||||
import type { Filter, PageFiltersStore } from "./page-filters/store";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { MenuActions } from "../menu/menu-actions";
|
||||
import { MenuItem } from "../menu";
|
||||
import { Checkbox } from "../checkbox";
|
||||
|
||||
@@ -4,30 +4,28 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { action } from "mobx";
|
||||
import { beforeFrameStartsInjectionToken } from "../../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../../../before-frame-starts/tokens";
|
||||
import ipcRendererInjectable from "../../../utils/channel/ipc-renderer.injectable";
|
||||
import topBarStateInjectable from "./state.injectable";
|
||||
|
||||
// TODO: replace with a SyncBox
|
||||
const startTopbarStateSyncInjectable = getInjectable({
|
||||
id: "start-topbar-state-sync",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(topBarStateInjectable);
|
||||
const ipcRenderer = di.inject(ipcRendererInjectable);
|
||||
instantiate: (di) => ({
|
||||
id: "start-topbar-state-sync",
|
||||
run: () => {
|
||||
const state = di.inject(topBarStateInjectable);
|
||||
const ipcRenderer = di.inject(ipcRendererInjectable);
|
||||
|
||||
return {
|
||||
id: "start-topbar-state-sync",
|
||||
run: () => {
|
||||
ipcRenderer.on("history:can-go-back", action((event, canGoBack: boolean) => {
|
||||
state.prevEnabled = canGoBack;
|
||||
}));
|
||||
ipcRenderer.on("history:can-go-back", action((event, canGoBack: boolean) => {
|
||||
state.prevEnabled = canGoBack;
|
||||
}));
|
||||
|
||||
ipcRenderer.on("history:can-go-forward", action((event, canGoForward: boolean) => {
|
||||
state.nextEnabled = canGoForward;
|
||||
}));
|
||||
},
|
||||
};
|
||||
},
|
||||
ipcRenderer.on("history:can-go-forward", action((event, canGoForward: boolean) => {
|
||||
state.nextEnabled = canGoForward;
|
||||
}));
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import toggleMaximizeWindowInjectable from "./toggle-maximize-window/toggle-maxi
|
||||
import topBarStateInjectable from "./state.injectable";
|
||||
import platformInjectable from "../../../../common/vars/platform.injectable";
|
||||
import goForwardInjectable from "./top-bar-items/navigation-to-forward/go-forward/go-forward.injectable";
|
||||
import currentlyInClusterFrameInjectable from "../../../routes/currently-in-cluster-frame.injectable";
|
||||
|
||||
describe("<TopBar/>", () => {
|
||||
let di: DiContainer;
|
||||
@@ -42,6 +43,7 @@ describe("<TopBar/>", () => {
|
||||
di.override(closeWindowInjectable, () => closeWindow = jest.fn());
|
||||
di.override(maximizeWindowInjectable, () => maximizeWindow = jest.fn());
|
||||
di.override(toggleMaximizeWindowInjectable, () => toggleMaximizeWindow = jest.fn());
|
||||
di.override(currentlyInClusterFrameInjectable, () => false);
|
||||
|
||||
render = renderFor(di);
|
||||
});
|
||||
|
||||
@@ -6,17 +6,27 @@
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import moment from "moment-timezone";
|
||||
import { UserStore } from "../../../common/user-store";
|
||||
import type { UserStore } from "../../../common/user-store";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import userStoreInjectable from "../../../common/user-store/user-store.injectable";
|
||||
|
||||
export interface LocaleDateProps {
|
||||
date: string;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class LocaleDate extends React.Component<LocaleDateProps> {
|
||||
render() {
|
||||
const { date } = this.props;
|
||||
|
||||
return moment.tz(date, UserStore.getInstance().localeTimezone).format();
|
||||
}
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
}
|
||||
|
||||
const NonInjectedLocaleDate = observer(({ date, userStore }: LocaleDateProps & Dependencies) => (
|
||||
<>
|
||||
{`${moment.tz(date, userStore.localeTimezone).format()}`}
|
||||
</>
|
||||
));
|
||||
|
||||
export const LocaleDate = withInjectables<Dependencies, LocaleDateProps>(NonInjectedLocaleDate, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -14,7 +14,7 @@ import { type MonacoValidator, monacoValidators } from "./monaco-validators";
|
||||
import { debounce, merge } from "lodash";
|
||||
import { autoBind, cssNames, disposer } from "../../utils";
|
||||
import type { UserStore } from "../../../common/user-store";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import userStoreInjectable from "../../../common/user-store/user-store.injectable";
|
||||
import activeThemeInjectable from "../../themes/active.injectable";
|
||||
|
||||
@@ -4,27 +4,16 @@
|
||||
*/
|
||||
|
||||
// Monaco editor themes customization
|
||||
import { editor } from "monaco-editor";
|
||||
import cloudsMidnight from "./monaco-themes/clouds-midnight.json";
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { editor } from "monaco-editor";
|
||||
|
||||
export type MonacoTheme = "vs" | "vs-dark" | "hc-black" | MonacoCustomTheme;
|
||||
export type MonacoCustomTheme = "clouds-midnight";
|
||||
|
||||
export interface MonacoThemeData extends editor.IStandaloneThemeData {
|
||||
name?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
// Registered names could be then used in "themes/*.json" in "{monacoTheme: [name]}"
|
||||
export const customThemes: Partial<Record<MonacoCustomTheme, MonacoThemeData>> = {
|
||||
"clouds-midnight": cloudsMidnight as MonacoThemeData,
|
||||
};
|
||||
|
||||
export function registerCustomThemes(): void {
|
||||
Object.entries(customThemes).forEach(([name, theme]) => {
|
||||
editor.defineTheme(name, theme);
|
||||
});
|
||||
}
|
||||
|
||||
export async function loadCustomTheme(name: string): Promise<MonacoThemeData> {
|
||||
return import(`./monaco-themes/${name}.json`);
|
||||
}
|
||||
export const customMonacoThemeInjectionToken = getInjectionToken<MonacoThemeData>({
|
||||
id: "custom-monaco-theme-token",
|
||||
});
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { customMonacoThemeInjectionToken } from "../monaco-themes";
|
||||
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
|
||||
const cloudsMidnightThemeInjectable = getInjectable({
|
||||
id: "clouds-midnight-theme",
|
||||
instantiate: () => ({
|
||||
"name": "clouds-midnight",
|
||||
"base": "vs-dark" as const,
|
||||
"inherit": true,
|
||||
"rules": [
|
||||
{
|
||||
"background": "191919",
|
||||
"token": "",
|
||||
},
|
||||
{
|
||||
"foreground": "3c403b",
|
||||
"token": "comment",
|
||||
},
|
||||
{
|
||||
"foreground": "5d90cd",
|
||||
"token": "string",
|
||||
},
|
||||
{
|
||||
"foreground": "46a609",
|
||||
"token": "constant.numeric",
|
||||
},
|
||||
{
|
||||
"foreground": "39946a",
|
||||
"token": "constant.language",
|
||||
},
|
||||
{
|
||||
"foreground": "927c5d",
|
||||
"token": "keyword",
|
||||
},
|
||||
{
|
||||
"foreground": "927c5d",
|
||||
"token": "support.constant.property-value",
|
||||
},
|
||||
{
|
||||
"foreground": "927c5d",
|
||||
"token": "constant.other.color",
|
||||
},
|
||||
{
|
||||
"foreground": "366f1a",
|
||||
"token": "keyword.other.unit",
|
||||
},
|
||||
{
|
||||
"foreground": "a46763",
|
||||
"token": "entity.other.attribute-name.html",
|
||||
},
|
||||
{
|
||||
"foreground": "4b4b4b",
|
||||
"token": "keyword.operator",
|
||||
},
|
||||
{
|
||||
"foreground": "e92e2e",
|
||||
"token": "storage",
|
||||
},
|
||||
{
|
||||
"foreground": "858585",
|
||||
"token": "entity.other.inherited-class",
|
||||
},
|
||||
{
|
||||
"foreground": "606060",
|
||||
"token": "entity.name.tag",
|
||||
},
|
||||
{
|
||||
"foreground": "a165ac",
|
||||
"token": "constant.character.entity",
|
||||
},
|
||||
{
|
||||
"foreground": "a165ac",
|
||||
"token": "support.class.js",
|
||||
},
|
||||
{
|
||||
"foreground": "606060",
|
||||
"token": "entity.other.attribute-name",
|
||||
},
|
||||
{
|
||||
"foreground": "e92e2e",
|
||||
"token": "meta.selector.css",
|
||||
},
|
||||
{
|
||||
"foreground": "e92e2e",
|
||||
"token": "entity.name.tag.css",
|
||||
},
|
||||
{
|
||||
"foreground": "e92e2e",
|
||||
"token": "entity.other.attribute-name.id.css",
|
||||
},
|
||||
{
|
||||
"foreground": "e92e2e",
|
||||
"token": "entity.other.attribute-name.class.css",
|
||||
},
|
||||
{
|
||||
"foreground": "616161",
|
||||
"token": "meta.property-name.css",
|
||||
},
|
||||
{
|
||||
"foreground": "e92e2e",
|
||||
"token": "support.function",
|
||||
},
|
||||
{
|
||||
"foreground": "ffffff",
|
||||
"background": "e92e2e",
|
||||
"token": "invalid",
|
||||
},
|
||||
{
|
||||
"foreground": "e92e2e",
|
||||
"token": "punctuation.section.embedded",
|
||||
},
|
||||
{
|
||||
"foreground": "606060",
|
||||
"token": "punctuation.definition.tag",
|
||||
},
|
||||
{
|
||||
"foreground": "a165ac",
|
||||
"token": "constant.other.color.rgb-value.css",
|
||||
},
|
||||
{
|
||||
"foreground": "a165ac",
|
||||
"token": "support.constant.property-value.css",
|
||||
},
|
||||
],
|
||||
"colors": {
|
||||
"editor.foreground": "#929292",
|
||||
"editor.background": "#191919",
|
||||
"editor.selectionBackground": "#000000",
|
||||
"editor.lineHighlightBackground": "#D7D7D708",
|
||||
"editorCursor.foreground": "#7DA5DC",
|
||||
"editorWhitespace.foreground": "#BFBFBF",
|
||||
},
|
||||
}),
|
||||
injectionToken: customMonacoThemeInjectionToken,
|
||||
});
|
||||
|
||||
export default cloudsMidnightThemeInjectable;
|
||||
@@ -3,17 +3,19 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { FileFilter, OpenDialogOptions } from "electron";
|
||||
import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
import type { OpenPathPickingDialog } from "../../../features/path-picking-dialog/renderer/pick-paths.injectable";
|
||||
import openPathPickingDialogInjectable from "../../../features/path-picking-dialog/renderer/pick-paths.injectable";
|
||||
import { cssNames } from "../../utils";
|
||||
import { Button } from "../button";
|
||||
import { requestOpenFilePickingDialog } from "../../ipc";
|
||||
|
||||
export interface PathPickOpts {
|
||||
label: string;
|
||||
onPick?: (paths: string[]) => any;
|
||||
onCancel?: () => any;
|
||||
message: string;
|
||||
onPick?: (paths: string[]) => void | Promise<void>;
|
||||
onCancel?: () => void | Promise<void>;
|
||||
defaultPath?: string;
|
||||
buttonLabel?: string;
|
||||
filters?: FileFilter[];
|
||||
@@ -26,40 +28,32 @@ export interface PathPickerProps extends PathPickOpts {
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class PathPicker extends React.Component<PathPickerProps> {
|
||||
static async pick(opts: PathPickOpts) {
|
||||
const { onPick, onCancel, label, ...dialogOptions } = opts;
|
||||
|
||||
const { canceled, filePaths } = await requestOpenFilePickingDialog({
|
||||
message: label,
|
||||
...dialogOptions,
|
||||
});
|
||||
|
||||
if (canceled) {
|
||||
await onCancel?.();
|
||||
} else {
|
||||
await onPick?.(filePaths);
|
||||
}
|
||||
}
|
||||
|
||||
async onClick() {
|
||||
const { className, disabled, ...pickOpts } = this.props;
|
||||
|
||||
return PathPicker.pick(pickOpts);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, label, disabled } = this.props;
|
||||
|
||||
return (
|
||||
<Button
|
||||
primary
|
||||
label={label}
|
||||
disabled={disabled}
|
||||
className={cssNames("PathPicker", className)}
|
||||
onClick={() => void this.onClick()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
interface Dependencies {
|
||||
openPathPickingDialog: OpenPathPickingDialog;
|
||||
}
|
||||
|
||||
const NonInjectedPathPicker = observer((props: PathPickerProps & Dependencies) => {
|
||||
const {
|
||||
className,
|
||||
disabled,
|
||||
openPathPickingDialog,
|
||||
...pickOpts
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Button
|
||||
primary
|
||||
label={pickOpts.message}
|
||||
disabled={disabled}
|
||||
className={cssNames("PathPicker", className)}
|
||||
onClick={() => void openPathPickingDialog(pickOpts)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export const PathPicker = withInjectables<Dependencies, PathPickerProps>(NonInjectedPathPicker, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
openPathPickingDialog: di.inject(openPathPickingDialogInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import { action, computed, makeObservable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import ReactSelect, { components, createFilter } from "react-select";
|
||||
import type { Props as ReactSelectProps, GroupBase, MultiValue, OptionsOrGroups, PropsValue, SingleValue } from "react-select";
|
||||
import type { LensTheme } from "../../themes/store";
|
||||
import type { LensTheme } from "../../themes/lens-theme";
|
||||
import { autoBind, cssNames } from "../../utils";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import activeThemeInjectable from "../../themes/active.injectable";
|
||||
|
||||
@@ -63,12 +63,15 @@ import type { FakeExtensionOptions } from "./get-extension-fake";
|
||||
import { getExtensionFakeForMain, getExtensionFakeForRenderer } from "./get-extension-fake";
|
||||
import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable";
|
||||
import { Namespace } from "../../../common/k8s-api/endpoints";
|
||||
import { overrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes";
|
||||
import { getOverrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes";
|
||||
import applicationMenuItemCompositeInjectable from "../../../features/application-menu/main/application-menu-item-composite.injectable";
|
||||
import { getCompositePaths } from "../../../common/utils/composite/get-composite-paths/get-composite-paths";
|
||||
import { discoverFor } from "./discovery-of-html-elements";
|
||||
import { findComposite } from "../../../common/utils/composite/find-composite/find-composite";
|
||||
import shouldStartHiddenInjectable from "../../../main/electron-app/features/should-start-hidden.injectable";
|
||||
import fsInjectable from "../../../common/fs/fs.injectable";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
import homeDirectoryPathInjectable from "../../../common/os/home-directory-path.injectable";
|
||||
|
||||
type Callback = (di: DiContainer) => void | Promise<void>;
|
||||
|
||||
@@ -114,6 +117,7 @@ export interface ApplicationBuilder {
|
||||
|
||||
allowKubeResource: (resourceName: KubeResource) => ApplicationBuilder;
|
||||
beforeApplicationStart: (callback: Callback) => ApplicationBuilder;
|
||||
afterApplicationStart: (callback: Callback) => ApplicationBuilder;
|
||||
beforeWindowStart: (callback: Callback) => ApplicationBuilder;
|
||||
afterWindowStart: (callback: Callback) => ApplicationBuilder;
|
||||
|
||||
@@ -170,12 +174,22 @@ export const getApplicationBuilder = () => {
|
||||
const { overrideForWindow, sendToWindow } = overrideChannels(mainDi);
|
||||
|
||||
const beforeApplicationStartCallbacks: Callback[] = [];
|
||||
const afterApplicationStartCallbacks: Callback[] = [];
|
||||
const beforeWindowStartCallbacks: Callback[] = [];
|
||||
const afterWindowStartCallbacks: Callback[] = [];
|
||||
|
||||
const fsState = new Map();
|
||||
const overrideFsWithFakes = getOverrideFsWithFakes();
|
||||
|
||||
overrideFsWithFakes(mainDi, fsState);
|
||||
overrideFsWithFakes(mainDi);
|
||||
|
||||
// Set up ~/.kube as existing as a folder
|
||||
{
|
||||
const { ensureDirSync } = mainDi.inject(fsInjectable);
|
||||
const joinPaths = mainDi.inject(joinPathsInjectable);
|
||||
const homeDirectoryPath = mainDi.inject(homeDirectoryPathInjectable);
|
||||
|
||||
ensureDirSync(joinPaths(homeDirectoryPath, ".kube"));
|
||||
}
|
||||
|
||||
let environment = environments.application;
|
||||
|
||||
@@ -210,7 +224,7 @@ export const getApplicationBuilder = () => {
|
||||
const windowDi = getRendererDi({ doGeneralOverrides: true });
|
||||
|
||||
overrideForWindow(windowDi, windowId);
|
||||
overrideFsWithFakes(windowDi, fsState);
|
||||
overrideFsWithFakes(windowDi);
|
||||
|
||||
runInAction(() => {
|
||||
windowDi.register(rendererExtensionsStateInjectable);
|
||||
@@ -276,6 +290,24 @@ export const getApplicationBuilder = () => {
|
||||
const namespaces = observable.set<string>();
|
||||
const namespaceItems = observable.array<Namespace>();
|
||||
const selectedNamespaces = observable.set<string>();
|
||||
const startMainApplication = mainDi.inject(startMainApplicationInjectable);
|
||||
|
||||
const startApplication = async ({ shouldStartHidden }: { shouldStartHidden: boolean }) => {
|
||||
mainDi.inject(lensProxyPortInjectable).set(42);
|
||||
|
||||
for (const callback of beforeApplicationStartCallbacks) {
|
||||
await callback(mainDi);
|
||||
}
|
||||
|
||||
mainDi.override(shouldStartHiddenInjectable, () => shouldStartHidden);
|
||||
await startMainApplication();
|
||||
|
||||
for (const callback of afterApplicationStartCallbacks) {
|
||||
await callback(mainDi);
|
||||
}
|
||||
|
||||
applicationHasStarted = true;
|
||||
};
|
||||
|
||||
const builder: ApplicationBuilder = {
|
||||
mainDi,
|
||||
@@ -556,7 +588,7 @@ export const getApplicationBuilder = () => {
|
||||
},
|
||||
|
||||
enable: (...extensions) => {
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
builder.afterWindowStart((windowDi) => {
|
||||
const rendererExtensionInstances = extensions.map((options) =>
|
||||
getExtensionFakeForRenderer(
|
||||
windowDi,
|
||||
@@ -571,7 +603,7 @@ export const getApplicationBuilder = () => {
|
||||
);
|
||||
});
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
builder.afterApplicationStart((mainDi) => {
|
||||
const mainExtensionInstances = extensions.map((extension) =>
|
||||
getExtensionFakeForMain(mainDi, extension.id, extension.name, extension.mainOptions || {}),
|
||||
);
|
||||
@@ -585,7 +617,7 @@ export const getApplicationBuilder = () => {
|
||||
},
|
||||
|
||||
disable: (...extensions) => {
|
||||
builder.beforeWindowStart(windowDi => {
|
||||
builder.afterWindowStart(windowDi => {
|
||||
extensions
|
||||
.map((ext) => ext.id)
|
||||
.forEach(
|
||||
@@ -593,7 +625,7 @@ export const getApplicationBuilder = () => {
|
||||
);
|
||||
});
|
||||
|
||||
builder.beforeApplicationStart(mainDi => {
|
||||
builder.afterApplicationStart(mainDi => {
|
||||
extensions
|
||||
.map((ext) => ext.id)
|
||||
.forEach(
|
||||
@@ -623,6 +655,16 @@ export const getApplicationBuilder = () => {
|
||||
return builder;
|
||||
},
|
||||
|
||||
afterApplicationStart(callback) {
|
||||
if (applicationHasStarted) {
|
||||
callback(mainDi);
|
||||
}
|
||||
|
||||
afterApplicationStartCallbacks.push(callback);
|
||||
|
||||
return builder;
|
||||
},
|
||||
|
||||
beforeWindowStart(callback) {
|
||||
const alreadyRenderedWindows = builder.applicationWindow.getAll();
|
||||
|
||||
@@ -648,29 +690,11 @@ export const getApplicationBuilder = () => {
|
||||
},
|
||||
|
||||
startHidden: async () => {
|
||||
mainDi.inject(lensProxyPortInjectable).set(42);
|
||||
|
||||
for (const callback of beforeApplicationStartCallbacks) {
|
||||
await callback(mainDi);
|
||||
}
|
||||
|
||||
mainDi.override(shouldStartHiddenInjectable, () => true);
|
||||
await mainDi.inject(startMainApplicationInjectable);
|
||||
|
||||
applicationHasStarted = true;
|
||||
await startApplication({ shouldStartHidden: true });
|
||||
},
|
||||
|
||||
async render() {
|
||||
mainDi.inject(lensProxyPortInjectable).set(42);
|
||||
|
||||
for (const callback of beforeApplicationStartCallbacks) {
|
||||
await callback(mainDi);
|
||||
}
|
||||
|
||||
mainDi.override(shouldStartHiddenInjectable, () => false);
|
||||
await mainDi.inject(startMainApplicationInjectable);
|
||||
|
||||
applicationHasStarted = true;
|
||||
await startApplication({ shouldStartHidden: false });
|
||||
|
||||
return builder
|
||||
.applicationWindow
|
||||
|
||||
@@ -25,6 +25,7 @@ import allowedResourcesInjectable from "../../cluster-frame-context/allowed-reso
|
||||
import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable";
|
||||
import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable";
|
||||
import { useFakeTime } from "../../../common/test-utils/use-fake-time";
|
||||
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
|
||||
|
||||
describe("<ClusterFrame />", () => {
|
||||
let render: () => RenderResult;
|
||||
@@ -45,6 +46,7 @@ describe("<ClusterFrame />", () => {
|
||||
di.override(legacyOnChannelListenInjectable, () => jest.fn().mockImplementation(() => jest.fn()));
|
||||
di.override(directoryForUserDataInjectable, () => "/some/irrelavent/path");
|
||||
di.override(storesAndApisCanBeCreatedInjectable, () => true);
|
||||
di.override(currentlyInClusterFrameInjectable, () => true);
|
||||
|
||||
useFakeTime("2000-01-01 12:00:00am");
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/tokens";
|
||||
import injectSystemCAsInjectable from "../../../common/certificate-authorities/inject-system-cas.injectable";
|
||||
|
||||
const setupSystemCaInjectable = getInjectable({
|
||||
|
||||
@@ -9,16 +9,9 @@ import { createContainer, isInjectable } from "@ogre-tools/injectable";
|
||||
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import requestFromChannelInjectable from "./utils/channel/request-from-channel.injectable";
|
||||
import loggerInjectable from "../common/logger.injectable";
|
||||
import { overrideFsWithFakes } from "../test-utils/override-fs-with-fakes";
|
||||
import { getOverrideFsWithFakes } from "../test-utils/override-fs-with-fakes";
|
||||
import { createMemoryHistory } from "history";
|
||||
import focusWindowInjectable from "./navigation/focus-window.injectable";
|
||||
import extensionsStoreInjectable from "../extensions/extensions-store/extensions-store.injectable";
|
||||
import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store";
|
||||
import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
||||
import type { FileSystemProvisionerStore } from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store";
|
||||
import userStoreInjectable from "../common/user-store/user-store.injectable";
|
||||
import type { UserStore } from "../common/user-store";
|
||||
import hotbarStoreInjectable from "../common/hotbars/store.injectable";
|
||||
import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-spawning-pool.injectable";
|
||||
import hostedClusterIdInjectable from "./cluster-frame-context/hosted-cluster-id.injectable";
|
||||
import historyInjectable from "./navigation/history.injectable";
|
||||
@@ -26,16 +19,14 @@ import { ApiManager } from "../common/k8s-api/api-manager";
|
||||
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
|
||||
import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectable";
|
||||
import apiManagerInjectable from "../common/k8s-api/api-manager/manager.injectable";
|
||||
import { observable, computed, runInAction } from "mobx";
|
||||
import { computed, runInAction } from "mobx";
|
||||
import requestAnimationFrameInjectable from "./components/animate/request-animation-frame.injectable";
|
||||
import getRandomIdInjectable from "../common/utils/get-random-id.injectable";
|
||||
import getFilePathsInjectable from "../features/helm-charts/child-features/preferences/renderer/adding-of-custom-helm-repository/helm-file-input/get-file-paths.injectable";
|
||||
import callForPublicHelmRepositoriesInjectable from "../features/helm-charts/child-features/preferences/renderer/adding-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable";
|
||||
import requestPublicHelmRepositoriesInjectable from "../features/helm-charts/child-features/preferences/renderer/adding-of-public-helm-repository/public-helm-repositories/request-public-helm-repositories.injectable";
|
||||
import platformInjectable from "../common/vars/platform.injectable";
|
||||
import startTopbarStateSyncInjectable from "./components/layout/top-bar/start-state-sync.injectable";
|
||||
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
|
||||
import watchHistoryStateInjectable from "./remote-helpers/watch-history-state.injectable";
|
||||
import type { HotbarStore } from "../common/hotbars/store";
|
||||
import cronJobTriggerDialogClusterFrameChildComponentInjectable from "./components/+workloads-cronjobs/cron-job-trigger-dialog-cluster-frame-child-component.injectable";
|
||||
import deploymentScaleDialogClusterFrameChildComponentInjectable from "./components/+workloads-deployments/scale/deployment-scale-dialog-cluster-frame-child-component.injectable";
|
||||
import replicasetScaleDialogClusterFrameChildComponentInjectable from "./components/+workloads-replicasets/scale-dialog/replicaset-scale-dialog-cluster-frame-child-component.injectable";
|
||||
@@ -50,7 +41,6 @@ import legacyOnChannelListenInjectable from "./ipc/legacy-channel-listen.injecta
|
||||
import storageSaveDelayInjectable from "./utils/create-storage/storage-save-delay.injectable";
|
||||
import environmentVariablesInjectable from "../common/utils/environment-variables.injectable";
|
||||
import type { GlobalOverride } from "../common/test-utils/get-global-override";
|
||||
import type { PartialDeep } from "type-fest";
|
||||
|
||||
export const getDiForUnitTesting = (
|
||||
opts: { doGeneralOverrides?: boolean } = {},
|
||||
@@ -141,40 +131,14 @@ export const getDiForUnitTesting = (
|
||||
|
||||
overrideFunctionalInjectables(di, [
|
||||
broadcastMessageInjectable,
|
||||
getFilePathsInjectable,
|
||||
callForPublicHelmRepositoriesInjectable,
|
||||
requestPublicHelmRepositoriesInjectable,
|
||||
]);
|
||||
|
||||
di.override(extensionsStoreInjectable, () => ({
|
||||
isEnabled: () => false,
|
||||
}) as Partial<ExtensionsStore> as ExtensionsStore);
|
||||
|
||||
di.override(hotbarStoreInjectable, () => ({
|
||||
getActive: () => ({
|
||||
name: "some-hotbar",
|
||||
items: [null, null, null, null, null, null, null, null, null, null, null, null],
|
||||
id: "some-hotbar",
|
||||
}),
|
||||
getDisplayIndex: () => "0",
|
||||
isAddedToActive: () => false,
|
||||
}) as Partial<HotbarStore> as HotbarStore);
|
||||
|
||||
di.override(fileSystemProvisionerStoreInjectable, () => ({}) as FileSystemProvisionerStore);
|
||||
|
||||
di.override(userStoreInjectable, () => ({
|
||||
isTableColumnHidden: () => false,
|
||||
extensionRegistryUrl: { customUrl: "some-custom-url" },
|
||||
syncKubeconfigEntries: observable.map(),
|
||||
terminalConfig: { fontSize: 42 },
|
||||
editorConfiguration: { minimap: {}, tabSize: 42, fontSize: 42 },
|
||||
load: () => {},
|
||||
} as PartialDeep<UserStore> as UserStore));
|
||||
|
||||
di.override(apiManagerInjectable, () => new ApiManager());
|
||||
|
||||
di.override(requestFromChannelInjectable, () => () => Promise.resolve(undefined as never));
|
||||
|
||||
overrideFsWithFakes(di);
|
||||
getOverrideFsWithFakes()(di);
|
||||
|
||||
di.override(focusWindowInjectable, () => () => {});
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getAllEntries } from "../../features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync";
|
||||
import { Notifications } from "../components/notifications";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import React from "react";
|
||||
import navigateToKubernetesPreferencesInjectable from "../../features/preferences/common/navigate-to-kubernetes-preferences.injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import discoverAllKubeconfigSyncKindsInjectable from "../../features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/discover-all-sync-kinds.injectable";
|
||||
import { action } from "mobx";
|
||||
|
||||
const addSyncEntriesInjectable = getInjectable({
|
||||
id: "add-sync-entries",
|
||||
@@ -16,12 +16,16 @@ const addSyncEntriesInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const userStore = di.inject(userStoreInjectable);
|
||||
const navigateToKubernetesPreferences = di.inject(navigateToKubernetesPreferencesInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const discoverAllKubeconfigSyncKinds = di.inject(discoverAllKubeconfigSyncKindsInjectable);
|
||||
|
||||
return async (filePaths: string[]) => {
|
||||
userStore.syncKubeconfigEntries.merge(
|
||||
await getAllEntries(filePaths, logger),
|
||||
);
|
||||
const kinds = await discoverAllKubeconfigSyncKinds(filePaths);
|
||||
|
||||
action(() => {
|
||||
for (const [path] of kinds) {
|
||||
userStore.syncKubeconfigEntries.set(path, {});
|
||||
}
|
||||
});
|
||||
|
||||
Notifications.ok((
|
||||
<div>
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubernetesClusterCategory } from "../../common/catalog-entities";
|
||||
import { isLinux, isWindows } from "../../common/vars";
|
||||
import { PathPicker } from "../components/path-picker";
|
||||
|
||||
interface Dependencies {
|
||||
navigateToAddCluster: () => void;
|
||||
addSyncEntries: (filePaths: string[]) => void;
|
||||
kubernetesClusterCategory: KubernetesClusterCategory;
|
||||
}
|
||||
|
||||
export function initCatalogCategoryRegistryEntries({
|
||||
navigateToAddCluster,
|
||||
addSyncEntries,
|
||||
kubernetesClusterCategory,
|
||||
} : Dependencies) {
|
||||
kubernetesClusterCategory.on("catalogAddMenu", ctx => {
|
||||
ctx.menuItems.push(
|
||||
{
|
||||
icon: "text_snippet",
|
||||
title: "Add from kubeconfig",
|
||||
onClick: navigateToAddCluster,
|
||||
},
|
||||
);
|
||||
|
||||
if (isWindows || isLinux) {
|
||||
ctx.menuItems.push(
|
||||
{
|
||||
icon: "create_new_folder",
|
||||
title: "Sync kubeconfig folder(s)",
|
||||
defaultAction: true,
|
||||
onClick: async () => {
|
||||
await PathPicker.pick({
|
||||
label: "Sync folder(s)",
|
||||
buttonLabel: "Sync",
|
||||
properties: ["showHiddenFiles", "multiSelections", "openDirectory"],
|
||||
onPick: addSyncEntries,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: "note_add",
|
||||
title: "Sync kubeconfig file(s)",
|
||||
onClick: async () => {
|
||||
await PathPicker.pick({
|
||||
label: "Sync file(s)",
|
||||
buttonLabel: "Sync",
|
||||
properties: ["showHiddenFiles", "multiSelections", "openFile"],
|
||||
onPick: addSyncEntries,
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
} else {
|
||||
ctx.menuItems.push(
|
||||
{
|
||||
icon: "create_new_folder",
|
||||
title: "Sync kubeconfig(s)",
|
||||
defaultAction: true,
|
||||
onClick: async () => {
|
||||
await PathPicker.pick({
|
||||
label: "Sync file(s)",
|
||||
buttonLabel: "Sync",
|
||||
properties: ["showHiddenFiles", "multiSelections", "openFile", "openDirectory"],
|
||||
onPick: addSyncEntries,
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import fs from "fs";
|
||||
import "../../common/catalog-entities/kubernetes-cluster";
|
||||
import { ClusterStore } from "../../common/cluster-store/cluster-store";
|
||||
import { catalogCategoryRegistry } from "../api/catalog-category-registry";
|
||||
import { WeblinkAddCommand } from "../components/catalog-entities/weblink-add-command";
|
||||
import { loadConfigFromString } from "../../common/kube-helpers";
|
||||
import type { OpenDeleteClusterDialog } from "../components/delete-cluster-dialog/open.injectable";
|
||||
|
||||
async function onClusterDelete(clusterId: string, openDeleteClusterDialog: OpenDeleteClusterDialog) {
|
||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||
|
||||
if (!cluster) {
|
||||
return console.warn("[KUBERNETES-CLUSTER]: cannot delete cluster, does not exist in store", { clusterId });
|
||||
}
|
||||
|
||||
const result = loadConfigFromString(await fs.promises.readFile(cluster.kubeConfigPath, "utf-8"));
|
||||
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
openDeleteClusterDialog({ cluster, config: result.config });
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
openCommandDialog: (component: React.ReactElement) => void;
|
||||
openDeleteClusterDialog: OpenDeleteClusterDialog;
|
||||
}
|
||||
|
||||
export function initCatalog({ openCommandDialog, openDeleteClusterDialog }: Dependencies) {
|
||||
catalogCategoryRegistry
|
||||
.getForGroupKind("entity.k8slens.dev", "WebLink")
|
||||
?.on("catalogAddMenu", ctx => {
|
||||
ctx.menuItems.push({
|
||||
title: "Add web link",
|
||||
icon: "public",
|
||||
onClick: () => openCommandDialog(<WeblinkAddCommand />),
|
||||
});
|
||||
});
|
||||
|
||||
catalogCategoryRegistry
|
||||
.getForGroupKind("entity.k8slens.dev", "KubernetesCluster")
|
||||
?.on("contextMenuOpen", (entity, context) => {
|
||||
if (entity.metadata?.source == "local") {
|
||||
context.menuItems.push({
|
||||
title: "Remove",
|
||||
icon: "delete",
|
||||
onClick: () => onClusterDelete(entity.getId(), openDeleteClusterDialog),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export * from "./catalog";
|
||||
export * from "./ipc";
|
||||
export * from "./catalog-category-registry";
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { ipcRendererOn } from "../../common/ipc";
|
||||
import type { ExtensionLoader } from "../../extensions/extension-loader";
|
||||
import type { LensRendererExtension } from "../../extensions/lens-renderer-extension";
|
||||
|
||||
export function initIpcRendererListeners(extensionLoader: ExtensionLoader) {
|
||||
ipcRendererOn("extension:navigate", (event, extId: string, pageId ?: string, params?: Record<string, any>) => {
|
||||
const ext = extensionLoader.getInstanceById(extId) as LensRendererExtension | undefined;
|
||||
|
||||
ext?.navigate(pageId, params);
|
||||
});
|
||||
}
|
||||
@@ -3,11 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { OpenDialogOptions } from "electron";
|
||||
import { clusterActivateHandler, clusterDisconnectHandler, clusterSetFrameIdHandler, clusterStates } from "../../common/ipc/cluster";
|
||||
import type { ClusterId, ClusterState } from "../../common/cluster-types";
|
||||
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel, type WindowAction } from "../../common/ipc/window";
|
||||
import { openFilePickingDialogChannel } from "../../common/ipc/dialog";
|
||||
import { extensionDiscoveryStateChannel, extensionLoaderFromMainChannel } from "../../common/ipc/extension-handling";
|
||||
import type { InstalledExtension } from "../../extensions/extension-discovery/extension-discovery";
|
||||
import type { LensExtensionId } from "../../extensions/lens-extension";
|
||||
@@ -44,10 +42,6 @@ export function requestWindowAction(type: WindowAction): Promise<void> {
|
||||
return requestMain(windowActionHandleChannel, type);
|
||||
}
|
||||
|
||||
export function requestOpenFilePickingDialog(opts: OpenDialogOptions): Promise<{ canceled: boolean; filePaths: string[] }> {
|
||||
return requestMain(openFilePickingDialogChannel, opts);
|
||||
}
|
||||
|
||||
export function requestSetClusterFrameId(clusterId: ClusterId): Promise<void> {
|
||||
return requestMain(clusterSetFrameIdHandler, clusterId);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import navigateToEntitySettingsInjectable from "../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable";
|
||||
import type { ListNamespaceForbiddenArgs } from "../../common/ipc/cluster";
|
||||
import { Notifications } from "../components/notifications";
|
||||
import { ClusterStore } from "../../common/cluster-store/cluster-store";
|
||||
import { Button } from "../components/button";
|
||||
import type { IpcRendererEvent } from "electron";
|
||||
import React from "react";
|
||||
import notificationsStoreInjectable from "../components/notifications/notifications-store.injectable";
|
||||
import { getMillisecondsFromUnixEpoch } from "../../common/utils/date/get-current-date-time";
|
||||
import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable";
|
||||
|
||||
const listNamespacesForbiddenHandlerInjectable = getInjectable({
|
||||
id: "list-namespaces-forbidden-handler",
|
||||
@@ -19,6 +19,7 @@ const listNamespacesForbiddenHandlerInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const navigateToEntitySettings = di.inject(navigateToEntitySettingsInjectable);
|
||||
const notificationsStore = di.inject(notificationsStoreInjectable);
|
||||
const getClusterById = di.inject(getClusterByIdInjectable);
|
||||
const notificationLastDisplayedAt = new Map<string, number>();
|
||||
const intervalBetweenNotifications = 1000 * 60; // 60s
|
||||
|
||||
@@ -52,7 +53,7 @@ const listNamespacesForbiddenHandlerInjectable = getInjectable({
|
||||
<b>Add Accessible Namespaces</b>
|
||||
<p>
|
||||
{"Cluster "}
|
||||
<b>{ClusterStore.getInstance().getById(clusterId)?.name ?? "<unknown cluster>"}</b>
|
||||
<b>{getClusterById(clusterId)?.name ?? "<unknown cluster>"}</b>
|
||||
{" does not have permissions to list namespaces. Please add the namespaces you have access to."}
|
||||
</p>
|
||||
<div className="flex gaps row align-left box grow">
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import addNewMonacoThemeInjectable from "./add-new-theme.injectable";
|
||||
|
||||
export default getGlobalOverride(addNewMonacoThemeInjectable, () => () => {});
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { editor } from "monaco-editor";
|
||||
import type { MonacoThemeData } from "../components/monaco-editor";
|
||||
|
||||
const addNewMonacoThemeInjectable = getInjectable({
|
||||
id: "add-new-monaco-theme",
|
||||
instantiate: () => (data: MonacoThemeData) => editor.defineTheme(data.name, data),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default addNewMonacoThemeInjectable;
|
||||
+2
@@ -15,6 +15,7 @@ import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.i
|
||||
|
||||
// TODO: Importing from features is not OK. Make protocol-router to comply with Open Closed Principle to allow moving implementation under a feature
|
||||
import navigateToPreferencesInjectable from "../../../features/preferences/common/navigate-to-preferences.injectable";
|
||||
import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable";
|
||||
|
||||
const bindProtocolAddRouteHandlersInjectable = getInjectable({
|
||||
id: "bind-protocol-add-route-handlers",
|
||||
@@ -29,6 +30,7 @@ const bindProtocolAddRouteHandlersInjectable = getInjectable({
|
||||
navigateToClusterView: di.inject(navigateToClusterViewInjectable),
|
||||
navigateToPreferences: di.inject(navigateToPreferencesInjectable),
|
||||
entityRegistry: di.inject(catalogEntityRegistryInjectable),
|
||||
getClusterById: di.inject(getClusterByIdInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
+5
-3
@@ -6,7 +6,6 @@
|
||||
import React from "react";
|
||||
import type { LensProtocolRouterRenderer } from "../lens-protocol-router-renderer/lens-protocol-router-renderer";
|
||||
import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry";
|
||||
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||
import {
|
||||
EXTENSION_NAME_MATCH,
|
||||
EXTENSION_PUBLISHER_MATCH,
|
||||
@@ -18,6 +17,7 @@ import type { NavigateToEntitySettings } from "../../../common/front-end-routing
|
||||
import type { NavigateToClusterView } from "../../../common/front-end-routing/routes/cluster-view/navigate-to-cluster-view.injectable";
|
||||
import assert from "assert";
|
||||
import type { AttemptInstallByInfo } from "../../components/+extensions/attempt-install-by-info.injectable";
|
||||
import type { GetClusterById } from "../../../common/cluster-store/get-by-id.injectable";
|
||||
|
||||
// TODO: make it so that the handlers are type safe and we don't need to do the asserts
|
||||
interface Dependencies {
|
||||
@@ -30,6 +30,7 @@ interface Dependencies {
|
||||
navigateToClusterView: NavigateToClusterView;
|
||||
navigateToPreferences: (tabId: string) => void;
|
||||
entityRegistry: CatalogEntityRegistry;
|
||||
getClusterById: GetClusterById;
|
||||
}
|
||||
|
||||
export const bindProtocolAddRouteHandlers = ({
|
||||
@@ -42,6 +43,7 @@ export const bindProtocolAddRouteHandlers = ({
|
||||
navigateToClusterView,
|
||||
navigateToPreferences,
|
||||
entityRegistry,
|
||||
getClusterById,
|
||||
}: Dependencies) => () => {
|
||||
lensProtocolRouterRenderer
|
||||
.addInternalHandler("/preferences", ({ search: { highlight: tabId }}) => {
|
||||
@@ -93,7 +95,7 @@ export const bindProtocolAddRouteHandlers = ({
|
||||
// Handlers below are deprecated and only kept for backward compact purposes
|
||||
.addInternalHandler("/cluster/:clusterId", ({ pathname: { clusterId }}) => {
|
||||
assert(clusterId);
|
||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||
const cluster = getClusterById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
navigateToClusterView(clusterId);
|
||||
@@ -109,7 +111,7 @@ export const bindProtocolAddRouteHandlers = ({
|
||||
})
|
||||
.addInternalHandler("/cluster/:clusterId/settings", ({ pathname: { clusterId }}) => {
|
||||
assert(clusterId);
|
||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||
const cluster = getClusterById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
navigateToEntitySettings(clusterId);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
const currentlyInClusterFrameInjectable = getInjectable({
|
||||
id: "currently-in-cluster-frame",
|
||||
instantiate: () => !process.isMainFrame,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default currentlyInClusterFrameInjectable;
|
||||
@@ -4,16 +4,32 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { runManyFor } from "../../common/runnable/run-many-for";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken, beforeClusterFrameStartsInjectionToken, beforeFrameStartsFirstInjectionToken, beforeMainFrameStartsInjectionToken } from "../before-frame-starts/tokens";
|
||||
import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable";
|
||||
|
||||
const startFrameInjectable = getInjectable({
|
||||
id: "start-frame",
|
||||
|
||||
// TODO: Consolidate contents of bootstrap.tsx here
|
||||
instantiate: (di) => async () => {
|
||||
const beforeFrameStarts = runManyFor(di)(beforeFrameStartsInjectionToken);
|
||||
instantiate: (di) => {
|
||||
const runMany = runManyFor(di);
|
||||
const beforeFrameStartsFirst = runMany(beforeFrameStartsFirstInjectionToken);
|
||||
const beforeMainFrameStarts = runMany(beforeMainFrameStartsInjectionToken);
|
||||
const beforeClusterFrameStarts = runMany(beforeClusterFrameStartsInjectionToken);
|
||||
const beforeFrameStarts = runMany(beforeFrameStartsInjectionToken);
|
||||
const currentlyInClusterFrame = di.inject(currentlyInClusterFrameInjectable);
|
||||
|
||||
await beforeFrameStarts();
|
||||
return async () => {
|
||||
await beforeFrameStartsFirst();
|
||||
|
||||
if (currentlyInClusterFrame) {
|
||||
await beforeClusterFrameStarts();
|
||||
} else {
|
||||
await beforeMainFrameStarts();
|
||||
}
|
||||
|
||||
await beforeFrameStarts();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -4,20 +4,21 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/tokens";
|
||||
import initDefaultUpdateChannelInjectable from "../vars/default-update-channel/init.injectable";
|
||||
|
||||
const initUserStoreInjectable = getInjectable({
|
||||
id: "init-user-store",
|
||||
instantiate: (di) => {
|
||||
const userStore = di.inject(userStoreInjectable);
|
||||
instantiate: (di) => ({
|
||||
id: "init-user-store",
|
||||
run: () => {
|
||||
// This must be done here so as to actually only be instantiated after the dependencies are
|
||||
const userStore = di.inject(userStoreInjectable);
|
||||
|
||||
return {
|
||||
id: "init-user-store",
|
||||
run: () => userStore.load(),
|
||||
runAfter: di.inject(initDefaultUpdateChannelInjectable),
|
||||
};
|
||||
},
|
||||
return userStore.load();
|
||||
},
|
||||
runAfter: di.inject(initDefaultUpdateChannelInjectable),
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { computed } from "mobx";
|
||||
import type { LensThemeType } from "./store";
|
||||
import themeStoreInjectable from "./store.injectable";
|
||||
import activeThemeInjectable from "./active.injectable";
|
||||
import type { LensThemeType } from "./lens-theme";
|
||||
|
||||
export type ActiveThemeType = IComputedValue<LensThemeType>;
|
||||
|
||||
@@ -14,9 +14,9 @@ const activeThemeTypeInjectable = getInjectable({
|
||||
id: "active-theme-type",
|
||||
|
||||
instantiate: (di) => {
|
||||
const store = di.inject(themeStoreInjectable);
|
||||
const activeTheme = di.inject(activeThemeInjectable);
|
||||
|
||||
return computed(() => store.activeTheme.type);
|
||||
return computed(() => activeTheme.get().type);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -3,15 +3,37 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import assert from "assert";
|
||||
import { computed } from "mobx";
|
||||
import themeStoreInjectable from "./store.injectable";
|
||||
import lensColorThemePreferenceInjectable from "../../common/user-store/lens-color-theme.injectable";
|
||||
import { lensThemeDeclarationInjectionToken } from "./declaration";
|
||||
import defaultLensThemeInjectable from "./default-theme.injectable";
|
||||
import systemThemeConfigurationInjectable from "./system-theme.injectable";
|
||||
import lensThemesInjectable from "./themes.injectable";
|
||||
|
||||
const activeThemeInjectable = getInjectable({
|
||||
id: "active-theme",
|
||||
instantiate: (di) => {
|
||||
const store = di.inject(themeStoreInjectable);
|
||||
const lensThemes = di.inject(lensThemesInjectable);
|
||||
const themeDecls = di.injectMany(lensThemeDeclarationInjectionToken);
|
||||
const lensColorThemePreference = di.inject(lensColorThemePreferenceInjectable);
|
||||
const systemThemeConfiguration = di.inject(systemThemeConfigurationInjectable);
|
||||
const defaultLensTheme = di.inject(defaultLensThemeInjectable);
|
||||
|
||||
return computed(() => store.activeTheme);
|
||||
return computed(() => {
|
||||
const pref = lensColorThemePreference.get();
|
||||
|
||||
if (pref.useSystemTheme) {
|
||||
const systemThemeType = systemThemeConfiguration.get();
|
||||
const matchingTheme = themeDecls.find(theme => theme.type === systemThemeType);
|
||||
|
||||
assert(matchingTheme, `Missing theme declaration for system theme "${systemThemeType}"`);
|
||||
|
||||
return matchingTheme;
|
||||
}
|
||||
|
||||
return lensThemes.get(pref.lensThemeId) ?? defaultLensTheme;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import { object } from "../utils";
|
||||
import type { LensTheme } from "./lens-theme";
|
||||
|
||||
export type ApplyLensTheme = (theme: LensTheme) => void;
|
||||
|
||||
const applyLensThemeInjectable = getInjectable({
|
||||
id: "apply-lens-theme",
|
||||
instantiate: (di): ApplyLensTheme => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const userStore = di.inject(userStoreInjectable);
|
||||
|
||||
return (theme) => {
|
||||
try {
|
||||
const colors = object.entries(theme.colors);
|
||||
|
||||
for (const [name, value] of colors) {
|
||||
document.documentElement.style.setProperty(`--${name}`, value);
|
||||
}
|
||||
|
||||
// Adding universal theme flag which can be used in component styles
|
||||
document.body.classList.toggle("theme-light", theme.type === "light");
|
||||
} catch (error) {
|
||||
logger.error("[THEME]: Failed to apply active theme", error);
|
||||
userStore.resetTheme();
|
||||
}
|
||||
};
|
||||
},
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default applyLensThemeInjectable;
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
|
||||
import applyLensThemeInjectable from "./apply-lens-theme.injectable";
|
||||
|
||||
export default getGlobalOverride(applyLensThemeInjectable, () => () => {});
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { ReadonlyDeep } from "type-fest";
|
||||
import type { LensTheme } from "./lens-theme";
|
||||
|
||||
export const lensThemeDeclarationInjectionToken = getInjectionToken<ReadonlyDeep<LensTheme>>({
|
||||
id: "lens-theme-declaration",
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { lensThemeDeclarationInjectionToken } from "./declaration";
|
||||
|
||||
const defaultLensThemeInjectable = getInjectable({
|
||||
id: "default-lens-theme",
|
||||
instantiate: (di) => {
|
||||
const themes = di.injectMany(lensThemeDeclarationInjectionToken);
|
||||
const [defaultTheme, ...rest] = themes.filter(theme => theme.isDefault);
|
||||
|
||||
if (rest.length > 0) {
|
||||
throw new Error("Multiple LensTheme's are declared as the default");
|
||||
}
|
||||
|
||||
if (!defaultTheme) {
|
||||
throw new Error("No LensTheme is declared as the default");
|
||||
}
|
||||
|
||||
return defaultTheme;
|
||||
},
|
||||
});
|
||||
|
||||
export default defaultLensThemeInjectable;
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { lensThemeDeclarationInjectionToken } from "./declaration";
|
||||
|
||||
const lensDarkThemeInjectable = getInjectable({
|
||||
id: "lens-dark-theme",
|
||||
instantiate: () => ({
|
||||
name: "Dark",
|
||||
type: "dark" as const,
|
||||
description: "Original Lens dark theme",
|
||||
author: "Mirantis",
|
||||
monacoTheme: "clouds-midnight" as const,
|
||||
colors: {
|
||||
blue: "#3d90ce",
|
||||
magenta: "#c93dce",
|
||||
golden: "#ffc63d",
|
||||
halfGray: "#87909c80",
|
||||
primary: "#3d90ce",
|
||||
textColorPrimary: "#8e9297",
|
||||
textColorSecondary: "#a0a0a0",
|
||||
textColorTertiary: "#909ba6",
|
||||
textColorAccent: "#ffffff",
|
||||
textColorDimmed: "#8e92978c",
|
||||
borderColor: "#4c5053",
|
||||
borderFaintColor: "#373a3e",
|
||||
mainBackground: "#1e2124",
|
||||
secondaryBackground: "#1e2125",
|
||||
contentColor: "#262b2f",
|
||||
layoutBackground: "#2e3136",
|
||||
layoutTabsBackground: "#252729",
|
||||
layoutTabsActiveColor: "#ffffff",
|
||||
layoutTabsLineColor: "#87909c80",
|
||||
sidebarBackground: "#36393e",
|
||||
sidebarLogoBackground: "#414448",
|
||||
sidebarActiveColor: "#ffffff",
|
||||
sidebarSubmenuActiveColor: "#ffffff",
|
||||
sidebarItemHoverBackground: "#3a3e44",
|
||||
badgeBackgroundColor: "#ffba44",
|
||||
buttonPrimaryBackground: "#3d90ce",
|
||||
buttonDefaultBackground: "#414448",
|
||||
buttonLightBackground: "#f1f1f1",
|
||||
buttonAccentBackground: "#e85555",
|
||||
buttonDisabledBackground: "#808080",
|
||||
tableBgcStripe: "#2a2d33",
|
||||
tableBgcSelected: "#383c42",
|
||||
tableHeaderBackground: "#262b2f",
|
||||
tableHeaderColor: "#ffffff",
|
||||
tableSelectedRowColor: "#ffffff",
|
||||
helmLogoBackground: "#ffffff",
|
||||
helmStableRepo: "#3d90ce",
|
||||
helmIncubatorRepo: "#ff7043",
|
||||
helmDescriptionHr: "#41474a",
|
||||
helmDescriptionBlockquoteColor: "#bbb",
|
||||
helmDescriptionBlockquoteBorder: "#8a8f93",
|
||||
helmDescriptionBlockquoteBackground: "#3b4348",
|
||||
helmDescriptionHeaders: "#3e4147",
|
||||
helmDescriptionH6: "#6a737d",
|
||||
helmDescriptionTdBorder: "#47494a",
|
||||
helmDescriptionTrBackground: "#1c2125",
|
||||
helmDescriptionCodeBackground: "#ffffff1a",
|
||||
helmDescriptionPreBackground: "#1b1f21",
|
||||
helmDescriptionPreColor: "#b4b5b4",
|
||||
colorSuccess: "#43a047",
|
||||
colorOk: "#4caf50",
|
||||
colorInfo: "#3d90ce",
|
||||
colorError: "#ce3933",
|
||||
colorSoftError: "#e85555",
|
||||
colorWarning: "#ff9800",
|
||||
colorVague: "#36393e",
|
||||
colorTerminated: "#4c5053",
|
||||
dockHeadBackground: "#2e3136",
|
||||
dockInfoBackground: "#1e2125",
|
||||
dockInfoBorderColor: "#303136",
|
||||
dockEditorBackground: "#000000",
|
||||
dockEditorTag: "#8e97a3",
|
||||
dockEditorKeyword: "#ffffff",
|
||||
dockEditorComment: "#808080",
|
||||
dockEditorActiveLineBackground: "#3a3d41",
|
||||
dockBadgeBackground: "#36393e",
|
||||
dockTabBorderColor: "#43424d",
|
||||
dockTabActiveBackground: "#3a3e45",
|
||||
logsBackground: "#000000",
|
||||
logsForeground: "#ffffff",
|
||||
logRowHoverBackground: "#35373a",
|
||||
dialogTextColor: "#87909c",
|
||||
dialogBackground: "#ffffff",
|
||||
dialogHeaderBackground: "#36393e",
|
||||
dialogFooterBackground: "#f4f4f4",
|
||||
drawerTogglerBackground: "#2f343a",
|
||||
drawerTitleText: "#ffffff",
|
||||
drawerSubtitleBackground: "#373a3e",
|
||||
drawerItemNameColor: "#87909c",
|
||||
drawerItemValueColor: "#a0a0a0",
|
||||
clusterMenuBackground: "#252729",
|
||||
clusterMenuBorderColor: "#252729",
|
||||
clusterMenuCellBackground: "#2e3136",
|
||||
clusterSettingsBackground: "#1e2124",
|
||||
addClusterIconColor: "#252729",
|
||||
boxShadow: "#0000003a",
|
||||
iconActiveColor: "#ffffff",
|
||||
iconActiveBackground: "#ffffff18",
|
||||
filterAreaBackground: "#23272b",
|
||||
chartLiveBarBackground: "#00000033",
|
||||
chartStripesColor: "#ffffff08",
|
||||
chartCapacityColor: "#4c545f",
|
||||
pieChartDefaultColor: "#30353a",
|
||||
inputOptionHoverColor: "#87909c",
|
||||
inputControlBackground: "#1e2125",
|
||||
inputControlBorder: "#414448",
|
||||
inputControlHoverBorder: "#474a4f",
|
||||
lineProgressBackground: "#414448",
|
||||
radioActiveBackground: "#36393e",
|
||||
menuActiveBackground: "#3d90ce",
|
||||
menuSelectedOptionBgc: "#36393e",
|
||||
canvasBackground: "#24292e",
|
||||
scrollBarColor: "#5f6064",
|
||||
settingsBackground: "#262b2e",
|
||||
settingsColor: "#909ba6",
|
||||
navSelectedBackground: "#262b2e",
|
||||
navHoverColor: "#dcddde",
|
||||
hrColor: "#ffffff0f",
|
||||
tooltipBackground: "#18191c",
|
||||
},
|
||||
terminalColors: {
|
||||
background: "#000000",
|
||||
foreground: "#ffffff",
|
||||
cursor: "#ffffff",
|
||||
cursorAccent: "#000000",
|
||||
selection: "#ffffff77",
|
||||
black: "#2e3436",
|
||||
red: "#cc0000",
|
||||
green: "#4e9a06",
|
||||
yellow: "#c4a000",
|
||||
blue: "#3465a4",
|
||||
magenta: "#75507b",
|
||||
cyan: "#06989a",
|
||||
white: "#d3d7cf",
|
||||
brightBlack: "#555753",
|
||||
brightRed: "#ef2929",
|
||||
brightGreen: "#8ae234",
|
||||
brightYellow: "#fce94f",
|
||||
brightBlue: "#729fcf",
|
||||
brightMagenta: "#ad7fa8",
|
||||
brightCyan: "#34e2e2",
|
||||
brightWhite: "#eeeeec",
|
||||
},
|
||||
isDefault: true,
|
||||
}),
|
||||
injectionToken: lensThemeDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default lensDarkThemeInjectable;
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { LensTheme } from "./store";
|
||||
|
||||
const lensDarkTheme: LensTheme = {
|
||||
"name": "Dark",
|
||||
"type": "dark",
|
||||
"description": "Original Lens dark theme",
|
||||
"author": "Mirantis",
|
||||
"monacoTheme": "clouds-midnight",
|
||||
"colors": {
|
||||
"blue": "#3d90ce",
|
||||
"magenta": "#c93dce",
|
||||
"golden": "#ffc63d",
|
||||
"halfGray": "#87909c80",
|
||||
"primary": "#3d90ce",
|
||||
"textColorPrimary": "#8e9297",
|
||||
"textColorSecondary": "#a0a0a0",
|
||||
"textColorTertiary": "#909ba6",
|
||||
"textColorAccent": "#ffffff",
|
||||
"textColorDimmed": "#8e92978c",
|
||||
"borderColor": "#4c5053",
|
||||
"borderFaintColor": "#373a3e",
|
||||
"mainBackground": "#1e2124",
|
||||
"secondaryBackground": "#1e2125",
|
||||
"contentColor": "#262b2f",
|
||||
"layoutBackground": "#2e3136",
|
||||
"layoutTabsBackground": "#252729",
|
||||
"layoutTabsActiveColor": "#ffffff",
|
||||
"layoutTabsLineColor": "#87909c80",
|
||||
"sidebarBackground": "#36393e",
|
||||
"sidebarLogoBackground": "#414448",
|
||||
"sidebarActiveColor": "#ffffff",
|
||||
"sidebarSubmenuActiveColor": "#ffffff",
|
||||
"sidebarItemHoverBackground": "#3a3e44",
|
||||
"badgeBackgroundColor": "#ffba44",
|
||||
"buttonPrimaryBackground": "#3d90ce",
|
||||
"buttonDefaultBackground": "#414448",
|
||||
"buttonLightBackground": "#f1f1f1",
|
||||
"buttonAccentBackground": "#e85555",
|
||||
"buttonDisabledBackground": "#808080",
|
||||
"tableBgcStripe": "#2a2d33",
|
||||
"tableBgcSelected": "#383c42",
|
||||
"tableHeaderBackground": "#262b2f",
|
||||
"tableHeaderColor": "#ffffff",
|
||||
"tableSelectedRowColor": "#ffffff",
|
||||
"helmLogoBackground": "#ffffff",
|
||||
"helmStableRepo": "#3d90ce",
|
||||
"helmIncubatorRepo": "#ff7043",
|
||||
"helmDescriptionHr": "#41474a",
|
||||
"helmDescriptionBlockquoteColor": "#bbb",
|
||||
"helmDescriptionBlockquoteBorder": "#8a8f93",
|
||||
"helmDescriptionBlockquoteBackground": "#3b4348",
|
||||
"helmDescriptionHeaders": "#3e4147",
|
||||
"helmDescriptionH6": "#6a737d",
|
||||
"helmDescriptionTdBorder": "#47494a",
|
||||
"helmDescriptionTrBackground": "#1c2125",
|
||||
"helmDescriptionCodeBackground": "#ffffff1a",
|
||||
"helmDescriptionPreBackground": "#1b1f21",
|
||||
"helmDescriptionPreColor": "#b4b5b4",
|
||||
"colorSuccess": "#43a047",
|
||||
"colorOk": "#4caf50",
|
||||
"colorInfo": "#3d90ce",
|
||||
"colorError": "#ce3933",
|
||||
"colorSoftError": "#e85555",
|
||||
"colorWarning": "#ff9800",
|
||||
"colorVague": "#36393e",
|
||||
"colorTerminated": "#4c5053",
|
||||
"dockHeadBackground": "#2e3136",
|
||||
"dockInfoBackground": "#1e2125",
|
||||
"dockInfoBorderColor": "#303136",
|
||||
"dockEditorBackground": "#000000",
|
||||
"dockEditorTag": "#8e97a3",
|
||||
"dockEditorKeyword": "#ffffff",
|
||||
"dockEditorComment": "#808080",
|
||||
"dockEditorActiveLineBackground": "#3a3d41",
|
||||
"dockBadgeBackground": "#36393e",
|
||||
"dockTabBorderColor": "#43424d",
|
||||
"dockTabActiveBackground": "#3a3e45",
|
||||
"logsBackground": "#000000",
|
||||
"logsForeground": "#ffffff",
|
||||
"logRowHoverBackground": "#35373a",
|
||||
"terminalBackground": "#000000",
|
||||
"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": "#555753",
|
||||
"terminalBrightRed": "#ef2929",
|
||||
"terminalBrightGreen": "#8ae234",
|
||||
"terminalBrightYellow": "#fce94f",
|
||||
"terminalBrightBlue": "#729fcf",
|
||||
"terminalBrightMagenta": "#ad7fa8",
|
||||
"terminalBrightCyan": "#34e2e2",
|
||||
"terminalBrightWhite": "#eeeeec",
|
||||
"dialogTextColor": "#87909c",
|
||||
"dialogBackground": "#ffffff",
|
||||
"dialogHeaderBackground": "#36393e",
|
||||
"dialogFooterBackground": "#f4f4f4",
|
||||
"drawerTogglerBackground": "#2f343a",
|
||||
"drawerTitleText": "#ffffff",
|
||||
"drawerSubtitleBackground": "#373a3e",
|
||||
"drawerItemNameColor": "#87909c",
|
||||
"drawerItemValueColor": "#a0a0a0",
|
||||
"clusterMenuBackground": "#252729",
|
||||
"clusterMenuBorderColor": "#252729",
|
||||
"clusterMenuCellBackground": "#2e3136",
|
||||
"clusterSettingsBackground": "#1e2124",
|
||||
"addClusterIconColor": "#252729",
|
||||
"boxShadow": "#0000003a",
|
||||
"iconActiveColor": "#ffffff",
|
||||
"iconActiveBackground": "#ffffff18",
|
||||
"filterAreaBackground": "#23272b",
|
||||
"chartLiveBarBackground": "#00000033",
|
||||
"chartStripesColor": "#ffffff08",
|
||||
"chartCapacityColor": "#4c545f",
|
||||
"pieChartDefaultColor": "#30353a",
|
||||
"inputOptionHoverColor": "#87909c",
|
||||
"inputControlBackground": "#1e2125",
|
||||
"inputControlBorder": "#414448",
|
||||
"inputControlHoverBorder": "#474a4f",
|
||||
"lineProgressBackground": "#414448",
|
||||
"radioActiveBackground": "#36393e",
|
||||
"menuActiveBackground": "#3d90ce",
|
||||
"menuSelectedOptionBgc": "#36393e",
|
||||
"canvasBackground": "#24292e",
|
||||
"scrollBarColor": "#5f6064",
|
||||
"settingsBackground": "#262b2e",
|
||||
"settingsColor": "#909ba6",
|
||||
"navSelectedBackground": "#262b2e",
|
||||
"navHoverColor": "#dcddde",
|
||||
"hrColor": "#ffffff0f",
|
||||
"tooltipBackground": "#18191c",
|
||||
},
|
||||
};
|
||||
|
||||
export default lensDarkTheme;
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { lensThemeDeclarationInjectionToken } from "./declaration";
|
||||
|
||||
const lensLightThemeInjectable = getInjectable({
|
||||
id: "lens-light-theme",
|
||||
instantiate: () => ({
|
||||
name: "Light",
|
||||
type: "light" as const,
|
||||
description: "Original Lens light theme",
|
||||
author: "Mirantis",
|
||||
monacoTheme: "vs" as const,
|
||||
colors: {
|
||||
blue: "#3d90ce",
|
||||
magenta: "#c93dce",
|
||||
golden: "#ffc63d",
|
||||
halfGray: "#87909c80",
|
||||
primary: "#3d90ce",
|
||||
textColorPrimary: "#555555",
|
||||
textColorSecondary: "#51575d",
|
||||
textColorTertiary: "#555555",
|
||||
textColorAccent: "#222222",
|
||||
textColorDimmed: "#5557598c",
|
||||
borderColor: "#c9cfd3",
|
||||
borderFaintColor: "#dfdfdf",
|
||||
mainBackground: "#f1f1f1",
|
||||
secondaryBackground: "#f2f3f5",
|
||||
contentColor: "#ffffff",
|
||||
layoutBackground: "#e8e8e8",
|
||||
layoutTabsBackground: "#f8f8f8",
|
||||
layoutTabsActiveColor: "#333333",
|
||||
layoutTabsLineColor: "#87909c80",
|
||||
sidebarLogoBackground: "#f1f1f1",
|
||||
sidebarActiveColor: "#ffffff",
|
||||
sidebarSubmenuActiveColor: "#3d90ce",
|
||||
sidebarBackground: "#e8e8e8",
|
||||
sidebarItemHoverBackground: "#f0f2f5",
|
||||
badgeBackgroundColor: "#ffba44",
|
||||
buttonPrimaryBackground: "#3d90ce",
|
||||
buttonDefaultBackground: "#414448",
|
||||
buttonLightBackground: "#f1f1f1",
|
||||
buttonAccentBackground: "#e85555",
|
||||
buttonDisabledBackground: "#808080",
|
||||
tableBgcStripe: "#f8f8f8",
|
||||
tableBgcSelected: "#f4f5f5",
|
||||
tableHeaderBackground: "#f1f1f1",
|
||||
tableHeaderColor: "#555555",
|
||||
tableSelectedRowColor: "#222222",
|
||||
helmLogoBackground: "#ffffff",
|
||||
helmStableRepo: "#3d90ce",
|
||||
helmIncubatorRepo: "#ff7043",
|
||||
helmDescriptionHr: "#dddddd",
|
||||
helmDescriptionBlockquoteColor: "#555555",
|
||||
helmDescriptionBlockquoteBorder: "#8a8f93",
|
||||
helmDescriptionBlockquoteBackground: "#eeeeee",
|
||||
helmDescriptionHeaders: "#3e4147",
|
||||
helmDescriptionH6: "#6a737d",
|
||||
helmDescriptionTdBorder: "#c6c6c6",
|
||||
helmDescriptionTrBackground: "#1c2125",
|
||||
helmDescriptionCodeBackground: "#ffffff1a",
|
||||
helmDescriptionPreBackground: "#eeeeee",
|
||||
helmDescriptionPreColor: "#555555",
|
||||
colorSuccess: "#206923",
|
||||
colorOk: "#399c3d",
|
||||
colorInfo: "#2d71a4",
|
||||
colorError: "#ce3933",
|
||||
colorSoftError: "#e85555",
|
||||
colorWarning: "#ff9800",
|
||||
colorVague: "#ededed",
|
||||
colorTerminated: "#9dabb5",
|
||||
dockHeadBackground: "#e8e8e8",
|
||||
dockInfoBackground: "#f3f3f3",
|
||||
dockInfoBorderColor: "#c9cfd3",
|
||||
dockEditorBackground: "#24292e",
|
||||
dockEditorTag: "#8e97a3",
|
||||
dockEditorKeyword: "#ffffff",
|
||||
dockEditorComment: "#808080",
|
||||
dockEditorActiveLineBackground: "#3a3d41",
|
||||
dockBadgeBackground: "#dedede",
|
||||
dockTabBorderColor: "#d5d4de",
|
||||
dockTabActiveBackground: "#ffffff",
|
||||
logsBackground: "#24292e",
|
||||
logsForeground: "#ffffff",
|
||||
logRowHoverBackground: "#35373a",
|
||||
dialogTextColor: "#87909c",
|
||||
dialogBackground: "#ffffff",
|
||||
dialogHeaderBackground: "#36393e",
|
||||
dialogFooterBackground: "#f4f4f4",
|
||||
drawerTogglerBackground: "#eaeced",
|
||||
drawerTitleText: "#ffffff",
|
||||
drawerSubtitleBackground: "#f1f1f1",
|
||||
drawerItemNameColor: "#727272",
|
||||
drawerItemValueColor: "#555555",
|
||||
clusterMenuBackground: "#d7d8da",
|
||||
clusterMenuBorderColor: "#c9cfd3",
|
||||
clusterMenuCellBackground: "#bbbbbb",
|
||||
clusterSettingsBackground: "#ffffff",
|
||||
addClusterIconColor: "#8d8d8d",
|
||||
boxShadow: "#0000003a",
|
||||
iconActiveColor: "#ffffff",
|
||||
iconActiveBackground: "#a6a6a694",
|
||||
filterAreaBackground: "#f7f7f7",
|
||||
chartLiveBarBackground: "#00000033",
|
||||
chartStripesColor: "#00000009",
|
||||
chartCapacityColor: "#cccccc",
|
||||
pieChartDefaultColor: "#efefef",
|
||||
inputOptionHoverColor: "#ffffff",
|
||||
inputControlBackground: "#f6f6f7",
|
||||
inputControlBorder: "#cccdcf",
|
||||
inputControlHoverBorder: "#b9bbbe",
|
||||
lineProgressBackground: "#e8e8e8",
|
||||
radioActiveBackground: "#f1f1f1",
|
||||
menuActiveBackground: "#3d90ce",
|
||||
menuSelectedOptionBgc: "#e8e8e8",
|
||||
canvasBackground: "#24292e",
|
||||
scrollBarColor: "#bbbbbb",
|
||||
settingsBackground: "#ffffff",
|
||||
settingsColor: "#555555",
|
||||
navSelectedBackground: "#ffffff",
|
||||
navHoverColor: "#2e3135",
|
||||
hrColor: "#06060714",
|
||||
tooltipBackground: "#ffffff",
|
||||
},
|
||||
terminalColors: {
|
||||
background: "#ffffff",
|
||||
foreground: "#2d2d2d",
|
||||
cursor: "#2d2d2d",
|
||||
cursorAccent: "#ffffff",
|
||||
selection: "#bfbfbf",
|
||||
black: "#2d2d2d",
|
||||
red: "#cd3734 ",
|
||||
green: "#18cf12",
|
||||
yellow: "#acb300",
|
||||
blue: "#3d90ce",
|
||||
magenta: "#c100cd",
|
||||
cyan: "#07c4b9",
|
||||
white: "#d3d7cf",
|
||||
brightBlack: "#a8a8a8",
|
||||
brightRed: "#ff6259",
|
||||
brightGreen: "#5cdb59",
|
||||
brightYellow: "#f8c000",
|
||||
brightBlue: "#008db6",
|
||||
brightMagenta: "#ee55f8",
|
||||
brightCyan: "#50e8df",
|
||||
brightWhite: "#eeeeec",
|
||||
},
|
||||
}),
|
||||
injectionToken: lensThemeDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default lensLightThemeInjectable;
|
||||
@@ -1,147 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { LensTheme } from "./store";
|
||||
|
||||
const lensLightTheme: LensTheme = {
|
||||
"name": "Light",
|
||||
"type": "light",
|
||||
"description": "Original Lens light theme",
|
||||
"author": "Mirantis",
|
||||
"monacoTheme": "vs",
|
||||
"colors": {
|
||||
"blue": "#3d90ce",
|
||||
"magenta": "#c93dce",
|
||||
"golden": "#ffc63d",
|
||||
"halfGray": "#87909c80",
|
||||
"primary": "#3d90ce",
|
||||
"textColorPrimary": "#555555",
|
||||
"textColorSecondary": "#51575d",
|
||||
"textColorTertiary": "#555555",
|
||||
"textColorAccent": "#222222",
|
||||
"textColorDimmed": "#5557598c",
|
||||
"borderColor": "#c9cfd3",
|
||||
"borderFaintColor": "#dfdfdf",
|
||||
"mainBackground": "#f1f1f1",
|
||||
"secondaryBackground": "#f2f3f5",
|
||||
"contentColor": "#ffffff",
|
||||
"layoutBackground": "#e8e8e8",
|
||||
"layoutTabsBackground": "#f8f8f8",
|
||||
"layoutTabsActiveColor": "#333333",
|
||||
"layoutTabsLineColor": "#87909c80",
|
||||
"sidebarLogoBackground": "#f1f1f1",
|
||||
"sidebarActiveColor": "#ffffff",
|
||||
"sidebarSubmenuActiveColor": "#3d90ce",
|
||||
"sidebarBackground": "#e8e8e8",
|
||||
"sidebarItemHoverBackground": "#f0f2f5",
|
||||
"badgeBackgroundColor": "#ffba44",
|
||||
"buttonPrimaryBackground": "#3d90ce",
|
||||
"buttonDefaultBackground": "#414448",
|
||||
"buttonLightBackground": "#f1f1f1",
|
||||
"buttonAccentBackground": "#e85555",
|
||||
"buttonDisabledBackground": "#808080",
|
||||
"tableBgcStripe": "#f8f8f8",
|
||||
"tableBgcSelected": "#f4f5f5",
|
||||
"tableHeaderBackground": "#f1f1f1",
|
||||
"tableHeaderColor": "#555555",
|
||||
"tableSelectedRowColor": "#222222",
|
||||
"helmLogoBackground": "#ffffff",
|
||||
"helmStableRepo": "#3d90ce",
|
||||
"helmIncubatorRepo": "#ff7043",
|
||||
"helmDescriptionHr": "#dddddd",
|
||||
"helmDescriptionBlockquoteColor": "#555555",
|
||||
"helmDescriptionBlockquoteBorder": "#8a8f93",
|
||||
"helmDescriptionBlockquoteBackground": "#eeeeee",
|
||||
"helmDescriptionHeaders": "#3e4147",
|
||||
"helmDescriptionH6": "#6a737d",
|
||||
"helmDescriptionTdBorder": "#c6c6c6",
|
||||
"helmDescriptionTrBackground": "#1c2125",
|
||||
"helmDescriptionCodeBackground": "#ffffff1a",
|
||||
"helmDescriptionPreBackground": "#eeeeee",
|
||||
"helmDescriptionPreColor": "#555555",
|
||||
"colorSuccess": "#206923",
|
||||
"colorOk": "#399c3d",
|
||||
"colorInfo": "#2d71a4",
|
||||
"colorError": "#ce3933",
|
||||
"colorSoftError": "#e85555",
|
||||
"colorWarning": "#ff9800",
|
||||
"colorVague": "#ededed",
|
||||
"colorTerminated": "#9dabb5",
|
||||
"dockHeadBackground": "#e8e8e8",
|
||||
"dockInfoBackground": "#f3f3f3",
|
||||
"dockInfoBorderColor": "#c9cfd3",
|
||||
"dockEditorBackground": "#24292e",
|
||||
"dockEditorTag": "#8e97a3",
|
||||
"dockEditorKeyword": "#ffffff",
|
||||
"dockEditorComment": "#808080",
|
||||
"dockEditorActiveLineBackground": "#3a3d41",
|
||||
"dockBadgeBackground": "#dedede",
|
||||
"dockTabBorderColor": "#d5d4de",
|
||||
"dockTabActiveBackground": "#ffffff",
|
||||
"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",
|
||||
"terminalWhite": "#d3d7cf",
|
||||
"terminalBrightBlack": "#a8a8a8",
|
||||
"terminalBrightRed": "#ff6259",
|
||||
"terminalBrightGreen": "#5cdb59",
|
||||
"terminalBrightYellow": "#f8c000",
|
||||
"terminalBrightBlue": "#008db6",
|
||||
"terminalBrightMagenta": "#ee55f8",
|
||||
"terminalBrightCyan": "#50e8df",
|
||||
"terminalBrightWhite": "#eeeeec",
|
||||
"dialogTextColor": "#87909c",
|
||||
"dialogBackground": "#ffffff",
|
||||
"dialogHeaderBackground": "#36393e",
|
||||
"dialogFooterBackground": "#f4f4f4",
|
||||
"drawerTogglerBackground": "#eaeced",
|
||||
"drawerTitleText": "#ffffff",
|
||||
"drawerSubtitleBackground": "#f1f1f1",
|
||||
"drawerItemNameColor": "#727272",
|
||||
"drawerItemValueColor": "#555555",
|
||||
"clusterMenuBackground": "#d7d8da",
|
||||
"clusterMenuBorderColor": "#c9cfd3",
|
||||
"clusterMenuCellBackground": "#bbbbbb",
|
||||
"clusterSettingsBackground": "#ffffff",
|
||||
"addClusterIconColor": "#8d8d8d",
|
||||
"boxShadow": "#0000003a",
|
||||
"iconActiveColor": "#ffffff",
|
||||
"iconActiveBackground": "#a6a6a694",
|
||||
"filterAreaBackground": "#f7f7f7",
|
||||
"chartLiveBarBackground": "#00000033",
|
||||
"chartStripesColor": "#00000009",
|
||||
"chartCapacityColor": "#cccccc",
|
||||
"pieChartDefaultColor": "#efefef",
|
||||
"inputOptionHoverColor": "#ffffff",
|
||||
"inputControlBackground": "#f6f6f7",
|
||||
"inputControlBorder": "#cccdcf",
|
||||
"inputControlHoverBorder": "#b9bbbe",
|
||||
"lineProgressBackground": "#e8e8e8",
|
||||
"radioActiveBackground": "#f1f1f1",
|
||||
"menuActiveBackground": "#3d90ce",
|
||||
"menuSelectedOptionBgc": "#e8e8e8",
|
||||
"canvasBackground": "#24292e",
|
||||
"scrollBarColor": "#bbbbbb",
|
||||
"settingsBackground": "#ffffff",
|
||||
"settingsColor": "#555555",
|
||||
"navSelectedBackground": "#ffffff",
|
||||
"navHoverColor": "#2e3135",
|
||||
"hrColor": "#06060714",
|
||||
"tooltipBackground": "#ffffff",
|
||||
},
|
||||
};
|
||||
|
||||
export default lensLightTheme;
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { MonacoTheme } from "../components/monaco-editor";
|
||||
|
||||
export type ThemeId = string;
|
||||
export type LensThemeType = "dark" | "light";
|
||||
export interface LensTheme {
|
||||
name: string;
|
||||
type: LensThemeType;
|
||||
colors: Record<LensColorName, string>;
|
||||
terminalColors: Partial<Record<TerminalColorName, string>>;
|
||||
description: string;
|
||||
author: string;
|
||||
monacoTheme: MonacoTheme;
|
||||
isDefault?: boolean;
|
||||
}
|
||||
|
||||
export type TerminalColorName =
|
||||
| "foreground"
|
||||
| "background"
|
||||
| "cursor"
|
||||
| "cursorAccent"
|
||||
| "selection"
|
||||
| "selectionForeground"
|
||||
| "black"
|
||||
| "red"
|
||||
| "green"
|
||||
| "yellow"
|
||||
| "blue"
|
||||
| "magenta"
|
||||
| "cyan"
|
||||
| "white"
|
||||
| "brightBlack"
|
||||
| "brightRed"
|
||||
| "brightGreen"
|
||||
| "brightYellow"
|
||||
| "brightBlue"
|
||||
| "brightMagenta"
|
||||
| "brightCyan"
|
||||
| "brightWhite";
|
||||
|
||||
export type LensColorName =
|
||||
| "blue"
|
||||
| "magenta"
|
||||
| "golden"
|
||||
| "halfGray"
|
||||
| "primary"
|
||||
| "textColorPrimary"
|
||||
| "textColorSecondary"
|
||||
| "textColorTertiary"
|
||||
| "textColorAccent"
|
||||
| "textColorDimmed"
|
||||
| "borderColor"
|
||||
| "borderFaintColor"
|
||||
| "mainBackground"
|
||||
| "secondaryBackground"
|
||||
| "contentColor"
|
||||
| "layoutBackground"
|
||||
| "layoutTabsBackground"
|
||||
| "layoutTabsActiveColor"
|
||||
| "layoutTabsLineColor"
|
||||
| "sidebarLogoBackground"
|
||||
| "sidebarActiveColor"
|
||||
| "sidebarSubmenuActiveColor"
|
||||
| "sidebarBackground"
|
||||
| "sidebarItemHoverBackground"
|
||||
| "badgeBackgroundColor"
|
||||
| "buttonPrimaryBackground"
|
||||
| "buttonDefaultBackground"
|
||||
| "buttonLightBackground"
|
||||
| "buttonAccentBackground"
|
||||
| "buttonDisabledBackground"
|
||||
| "tableBgcStripe"
|
||||
| "tableBgcSelected"
|
||||
| "tableHeaderBackground"
|
||||
| "tableHeaderColor"
|
||||
| "tableSelectedRowColor"
|
||||
| "helmLogoBackground"
|
||||
| "helmStableRepo"
|
||||
| "helmIncubatorRepo"
|
||||
| "helmDescriptionHr"
|
||||
| "helmDescriptionBlockquoteColor"
|
||||
| "helmDescriptionBlockquoteBorder"
|
||||
| "helmDescriptionBlockquoteBackground"
|
||||
| "helmDescriptionHeaders"
|
||||
| "helmDescriptionH6"
|
||||
| "helmDescriptionTdBorder"
|
||||
| "helmDescriptionTrBackground"
|
||||
| "helmDescriptionCodeBackground"
|
||||
| "helmDescriptionPreBackground"
|
||||
| "helmDescriptionPreColor"
|
||||
| "colorSuccess"
|
||||
| "colorOk"
|
||||
| "colorInfo"
|
||||
| "colorError"
|
||||
| "colorSoftError"
|
||||
| "colorWarning"
|
||||
| "colorVague"
|
||||
| "colorTerminated"
|
||||
| "dockHeadBackground"
|
||||
| "dockInfoBackground"
|
||||
| "dockInfoBorderColor"
|
||||
| "dockEditorBackground"
|
||||
| "dockEditorTag"
|
||||
| "dockEditorKeyword"
|
||||
| "dockEditorComment"
|
||||
| "dockEditorActiveLineBackground"
|
||||
| "dockBadgeBackground"
|
||||
| "dockTabBorderColor"
|
||||
| "dockTabActiveBackground"
|
||||
| "logsBackground"
|
||||
| "logsForeground"
|
||||
| "logRowHoverBackground"
|
||||
| "dialogTextColor"
|
||||
| "dialogBackground"
|
||||
| "dialogHeaderBackground"
|
||||
| "dialogFooterBackground"
|
||||
| "drawerTogglerBackground"
|
||||
| "drawerTitleText"
|
||||
| "drawerSubtitleBackground"
|
||||
| "drawerItemNameColor"
|
||||
| "drawerItemValueColor"
|
||||
| "clusterMenuBackground"
|
||||
| "clusterMenuBorderColor"
|
||||
| "clusterMenuCellBackground"
|
||||
| "clusterSettingsBackground"
|
||||
| "addClusterIconColor"
|
||||
| "boxShadow"
|
||||
| "iconActiveColor"
|
||||
| "iconActiveBackground"
|
||||
| "filterAreaBackground"
|
||||
| "chartLiveBarBackground"
|
||||
| "chartStripesColor"
|
||||
| "chartCapacityColor"
|
||||
| "pieChartDefaultColor"
|
||||
| "inputOptionHoverColor"
|
||||
| "inputControlBackground"
|
||||
| "inputControlBorder"
|
||||
| "inputControlHoverBorder"
|
||||
| "lineProgressBackground"
|
||||
| "radioActiveBackground"
|
||||
| "menuActiveBackground"
|
||||
| "menuSelectedOptionBgc"
|
||||
| "canvasBackground"
|
||||
| "scrollBarColor"
|
||||
| "settingsBackground"
|
||||
| "settingsColor"
|
||||
| "navSelectedBackground"
|
||||
| "navHoverColor"
|
||||
| "hrColor"
|
||||
| "tooltipBackground";
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { reaction } from "mobx";
|
||||
import initializeSystemThemeTypeInjectable from "../../features/theme/system-type/renderer/initialize.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../before-frame-starts/tokens";
|
||||
import initUserStoreInjectable from "../stores/init-user-store.injectable";
|
||||
import activeThemeInjectable from "./active.injectable";
|
||||
import applyLensThemeInjectable from "./apply-lens-theme.injectable";
|
||||
|
||||
const setupApplyActiveThemeInjectable = getInjectable({
|
||||
id: "setup-apply-active-theme",
|
||||
instantiate: (di) => ({
|
||||
id: "setup-apply-active-theme",
|
||||
run: () => {
|
||||
const activeTheme = di.inject(activeThemeInjectable);
|
||||
const applyLensTheme = di.inject(applyLensThemeInjectable);
|
||||
|
||||
reaction(
|
||||
() => activeTheme.get(),
|
||||
applyLensTheme,
|
||||
{
|
||||
fireImmediately: true,
|
||||
},
|
||||
);
|
||||
},
|
||||
runAfter: [
|
||||
di.inject(initializeSystemThemeTypeInjectable),
|
||||
di.inject(initUserStoreInjectable),
|
||||
],
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
export default setupApplyActiveThemeInjectable;
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||
import ipcRendererInjectable from "../utils/channel/ipc-renderer.injectable";
|
||||
import { ThemeStore } from "./store";
|
||||
|
||||
const themeStoreInjectable = getInjectable({
|
||||
id: "theme-store",
|
||||
|
||||
instantiate: (di) => new ThemeStore({
|
||||
ipcRenderer: di.inject(ipcRendererInjectable),
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
export default themeStoreInjectable;
|
||||
@@ -1,150 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { comparer, computed, makeObservable, observable, reaction } from "mobx";
|
||||
import { autoBind } from "../utils";
|
||||
import logger from "../../main/logger";
|
||||
import lensDarkTheme from "./lens-dark";
|
||||
import lensLightTheme from "./lens-light";
|
||||
import type { MonacoTheme } from "../components/monaco-editor";
|
||||
import { defaultThemeId } from "../../common/vars";
|
||||
import { camelCase } from "lodash";
|
||||
import type { IpcRenderer } from "electron";
|
||||
import { getNativeThemeChannel, setNativeThemeChannel } from "../../common/ipc/native-theme";
|
||||
import type { ReadonlyDeep } from "type-fest/source/readonly-deep";
|
||||
import assert from "assert";
|
||||
|
||||
export type ThemeId = string;
|
||||
export type LensThemeType = "dark" | "light";
|
||||
export interface LensTheme {
|
||||
name: string;
|
||||
type: LensThemeType;
|
||||
colors: Record<string, string>;
|
||||
description: string;
|
||||
author: string;
|
||||
monacoTheme: MonacoTheme;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
readonly userStore: {
|
||||
colorTheme: string;
|
||||
terminalTheme: ThemeId;
|
||||
resetTheme(): void;
|
||||
};
|
||||
readonly ipcRenderer: IpcRenderer;
|
||||
}
|
||||
|
||||
export class ThemeStore {
|
||||
private terminalColorPrefix = "terminal";
|
||||
|
||||
#themes = observable.map<ThemeId, LensTheme>({
|
||||
"lens-dark": lensDarkTheme,
|
||||
"lens-light": lensLightTheme,
|
||||
});
|
||||
|
||||
@observable private osNativeThemeType: "dark" | "light" | undefined;
|
||||
|
||||
@computed private get colorThemePreference(): ThemeId | "system" {
|
||||
return this.dependencies.userStore.colorTheme;
|
||||
}
|
||||
|
||||
@computed private get activeThemeId(): ThemeId {
|
||||
if (this.colorThemePreference === "system") {
|
||||
if (this.osNativeThemeType) {
|
||||
return `lens-${this.osNativeThemeType}`;
|
||||
} else {
|
||||
return defaultThemeId;
|
||||
}
|
||||
} else {
|
||||
return this.colorThemePreference;
|
||||
}
|
||||
}
|
||||
|
||||
@computed private get terminalThemeId(): ThemeId {
|
||||
return this.dependencies.userStore.terminalTheme;
|
||||
}
|
||||
|
||||
private readonly defaultTheme: LensTheme;
|
||||
|
||||
@computed get activeTheme(): LensTheme {
|
||||
return this.themes.get(this.activeThemeId) ?? this.defaultTheme;
|
||||
}
|
||||
|
||||
@computed private 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<string, string> {
|
||||
return Object.fromEntries(
|
||||
this.terminalColors.map(([name, color]) => [
|
||||
camelCase(name.replace(this.terminalColorPrefix, "")),
|
||||
color,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
get themes() {
|
||||
return this.#themes as ReadonlyDeep<Map<string, LensTheme>>;
|
||||
}
|
||||
|
||||
constructor(protected readonly dependencies: Dependencies) {
|
||||
makeObservable(this);
|
||||
autoBind(this);
|
||||
this.init();
|
||||
|
||||
const defaultTheme = this.#themes.get(defaultThemeId);
|
||||
|
||||
assert(defaultTheme, `${defaultThemeId} is invalid as there is no corresponding theme`);
|
||||
|
||||
this.defaultTheme = defaultTheme;
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.osNativeThemeType = await this.dependencies.ipcRenderer.invoke(getNativeThemeChannel);
|
||||
this.dependencies.ipcRenderer.on(setNativeThemeChannel, (event, theme: "dark" | "light") => {
|
||||
this.osNativeThemeType = theme;
|
||||
});
|
||||
|
||||
// auto-apply active theme
|
||||
reaction(() => ({
|
||||
themeId: this.activeThemeId,
|
||||
terminalThemeId: this.terminalThemeId,
|
||||
}), () => {
|
||||
try {
|
||||
this.applyActiveTheme();
|
||||
} catch (err) {
|
||||
logger.error(`Failed to apply active theme: ${err}`);
|
||||
this.dependencies.userStore.resetTheme();
|
||||
}
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
equals: comparer.shallow,
|
||||
});
|
||||
}
|
||||
|
||||
getThemeById(themeId: ThemeId): LensTheme | undefined {
|
||||
return this.themes.get(themeId);
|
||||
}
|
||||
|
||||
protected applyActiveTheme() {
|
||||
const colors = Object.entries({
|
||||
...this.activeTheme.colors,
|
||||
...Object.fromEntries(this.terminalColors),
|
||||
});
|
||||
|
||||
colors.forEach(([name, value]) => {
|
||||
document.documentElement.style.setProperty(`--${name}`, value);
|
||||
});
|
||||
|
||||
// Adding universal theme flag which can be used in component styles
|
||||
document.body.classList.toggle("theme-light", this.activeTheme.type === "light");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { observable } from "mobx";
|
||||
|
||||
const systemThemeConfigurationInjectable = getInjectable({
|
||||
id: "system-theme-configuration",
|
||||
instantiate: () => observable.box<"dark" | "light">("dark"),
|
||||
});
|
||||
|
||||
export default systemThemeConfigurationInjectable;
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import terminalThemePreferenceInjectable from "../../common/user-store/terminal-theme.injectable";
|
||||
import activeThemeInjectable from "./active.injectable";
|
||||
import lensThemesInjectable from "./themes.injectable";
|
||||
|
||||
const xtermColorThemeInjectable = getInjectable({
|
||||
id: "terminal-colors",
|
||||
instantiate: (di) => {
|
||||
const activeTheme = di.inject(activeThemeInjectable);
|
||||
const terminalThemePreference = di.inject(terminalThemePreferenceInjectable);
|
||||
const themes = di.inject(lensThemesInjectable);
|
||||
|
||||
const terminalTheme = computed(() => {
|
||||
const themePref = terminalThemePreference.get();
|
||||
|
||||
if (themePref.matchLensTheme) {
|
||||
return activeTheme.get();
|
||||
}
|
||||
|
||||
return themes.get(themePref.themeId) ?? activeTheme.get();
|
||||
});
|
||||
|
||||
return computed(() => terminalTheme.get().terminalColors);
|
||||
},
|
||||
});
|
||||
|
||||
export default xtermColorThemeInjectable;
|
||||
@@ -1,138 +0,0 @@
|
||||
|
||||
/*
|
||||
Generated Lens theme CSS-variables, don't edit manually.
|
||||
To refresh file run $: yarn run ts-node build/build_theme_vars.ts
|
||||
*/
|
||||
|
||||
:root {
|
||||
--blue: #3d90ce;
|
||||
--magenta: #c93dce;
|
||||
--golden: #ffc63d;
|
||||
--halfGray: #87909c80;
|
||||
--primary: #3d90ce;
|
||||
--textColorPrimary: #8e9297;
|
||||
--textColorSecondary: #a0a0a0;
|
||||
--textColorTertiary: #909ba6;
|
||||
--textColorAccent: #ffffff;
|
||||
--textColorDimmed: #8e92978c;
|
||||
--borderColor: #4c5053;
|
||||
--borderFaintColor: #373a3e;
|
||||
--mainBackground: #1e2124;
|
||||
--secondaryBackground: #1e2125;
|
||||
--contentColor: #262b2f;
|
||||
--layoutBackground: #2e3136;
|
||||
--layoutTabsBackground: #252729;
|
||||
--layoutTabsActiveColor: #ffffff;
|
||||
--layoutTabsLineColor: #87909c80;
|
||||
--sidebarBackground: #36393e;
|
||||
--sidebarLogoBackground: #414448;
|
||||
--sidebarActiveColor: #ffffff;
|
||||
--sidebarSubmenuActiveColor: #ffffff;
|
||||
--sidebarItemHoverBackground: #3a3e44;
|
||||
--badgeBackgroundColor: #ffba44;
|
||||
--buttonPrimaryBackground: #3d90ce;
|
||||
--buttonDefaultBackground: #414448;
|
||||
--buttonLightBackground: #f1f1f1;
|
||||
--buttonAccentBackground: #e85555;
|
||||
--buttonDisabledBackground: #808080;
|
||||
--tableBgcStripe: #2a2d33;
|
||||
--tableBgcSelected: #383c42;
|
||||
--tableHeaderBackground: #262b2f;
|
||||
--tableHeaderColor: #ffffff;
|
||||
--tableSelectedRowColor: #ffffff;
|
||||
--helmLogoBackground: #ffffff;
|
||||
--helmStableRepo: #3d90ce;
|
||||
--helmIncubatorRepo: #ff7043;
|
||||
--helmDescriptionHr: #41474a;
|
||||
--helmDescriptionBlockquoteColor: #bbb;
|
||||
--helmDescriptionBlockquoteBorder: #8a8f93;
|
||||
--helmDescriptionBlockquoteBackground: #3b4348;
|
||||
--helmDescriptionHeaders: #3e4147;
|
||||
--helmDescriptionH6: #6a737d;
|
||||
--helmDescriptionTdBorder: #47494a;
|
||||
--helmDescriptionTrBackground: #1c2125;
|
||||
--helmDescriptionCodeBackground: #ffffff1a;
|
||||
--helmDescriptionPreBackground: #1b1f21;
|
||||
--helmDescriptionPreColor: #b4b5b4;
|
||||
--colorSuccess: #43a047;
|
||||
--colorOk: #4caf50;
|
||||
--colorInfo: #3d90ce;
|
||||
--colorError: #ce3933;
|
||||
--colorSoftError: #e85555;
|
||||
--colorWarning: #ff9800;
|
||||
--colorVague: #36393e;
|
||||
--colorTerminated: #4c5053;
|
||||
--dockHeadBackground: #2e3136;
|
||||
--dockInfoBackground: #1e2125;
|
||||
--dockInfoBorderColor: #303136;
|
||||
--dockEditorBackground: #000000;
|
||||
--dockEditorTag: #8e97a3;
|
||||
--dockEditorKeyword: #ffffff;
|
||||
--dockEditorComment: #808080;
|
||||
--dockEditorActiveLineBackground: #3a3d41;
|
||||
--dockBadgeBackground: #36393e;
|
||||
--dockTabBorderColor: #43424d;
|
||||
--dockTabActiveBackground: #3a3e45;
|
||||
--logsBackground: #000000;
|
||||
--logsForeground: #ffffff;
|
||||
--logRowHoverBackground: #35373a;
|
||||
--terminalBackground: #000000;
|
||||
--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: #555753;
|
||||
--terminalBrightRed: #ef2929;
|
||||
--terminalBrightGreen: #8ae234;
|
||||
--terminalBrightYellow: #fce94f;
|
||||
--terminalBrightBlue: #729fcf;
|
||||
--terminalBrightMagenta: #ad7fa8;
|
||||
--terminalBrightCyan: #34e2e2;
|
||||
--terminalBrightWhite: #eeeeec;
|
||||
--dialogTextColor: #87909c;
|
||||
--dialogBackground: #ffffff;
|
||||
--dialogHeaderBackground: #36393e;
|
||||
--dialogFooterBackground: #f4f4f4;
|
||||
--drawerTogglerBackground: #2f343a;
|
||||
--drawerTitleText: #ffffff;
|
||||
--drawerSubtitleBackground: #373a3e;
|
||||
--drawerItemNameColor: #87909c;
|
||||
--drawerItemValueColor: #a0a0a0;
|
||||
--clusterMenuBackground: #252729;
|
||||
--clusterMenuBorderColor: #252729;
|
||||
--clusterMenuCellBackground: #2e3136;
|
||||
--clusterSettingsBackground: #1e2124;
|
||||
--addClusterIconColor: #252729;
|
||||
--boxShadow: #0000003a;
|
||||
--iconActiveColor: #ffffff;
|
||||
--iconActiveBackground: #ffffff18;
|
||||
--filterAreaBackground: #23272b;
|
||||
--chartLiveBarBackground: #00000033;
|
||||
--chartStripesColor: #ffffff08;
|
||||
--chartCapacityColor: #4c545f;
|
||||
--pieChartDefaultColor: #30353a;
|
||||
--inputOptionHoverColor: #87909c;
|
||||
--inputControlBackground: #1e2125;
|
||||
--inputControlBorder: #414448;
|
||||
--inputControlHoverBorder: #474a4f;
|
||||
--lineProgressBackground: #414448;
|
||||
--radioActiveBackground: #36393e;
|
||||
--menuActiveBackground: #3d90ce;
|
||||
--menuSelectedOptionBgc: #36393e;
|
||||
--canvasBackground: #24292e;
|
||||
--scrollBarColor: #5f6064;
|
||||
--settingsBackground: #262b2e;
|
||||
--settingsColor: #909ba6;
|
||||
--navSelectedBackground: #262b2e;
|
||||
--navHoverColor: #dcddde;
|
||||
--hrColor: #ffffff0f;
|
||||
--tooltipBackground: #18191c;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { lensThemeDeclarationInjectionToken } from "./declaration";
|
||||
|
||||
const lensThemesInjectable = getInjectable({
|
||||
id: "lens-themes",
|
||||
instantiate: (di) => {
|
||||
const themes = di.injectMany(lensThemeDeclarationInjectionToken);
|
||||
|
||||
return new Map(themes.map(theme => [theme.name, theme]));
|
||||
},
|
||||
});
|
||||
|
||||
export default lensThemesInjectable;
|
||||
@@ -6,7 +6,7 @@
|
||||
import { observable, reaction } from "mobx";
|
||||
import { StorageHelper } from "../storageHelper";
|
||||
import { delay } from "../../../common/utils/delay";
|
||||
import { toJS } from "../../../common/utils";
|
||||
import { noop, toJS } from "../../../common/utils";
|
||||
|
||||
interface StorageModel {
|
||||
[prop: string]: any /*json-serializable*/;
|
||||
@@ -26,7 +26,15 @@ describe("renderer/utils/StorageHelper", () => {
|
||||
message: "saved-before", // pretending as previously saved data
|
||||
});
|
||||
|
||||
storageHelper = new StorageHelper<StorageModel>(storageKey, {
|
||||
storageHelper = new StorageHelper<StorageModel>({
|
||||
logger: {
|
||||
debug: noop,
|
||||
error: noop,
|
||||
info: noop,
|
||||
silly: noop,
|
||||
warn: noop,
|
||||
},
|
||||
}, storageKey, {
|
||||
autoInit: false,
|
||||
defaultValue: {
|
||||
message: "blabla",
|
||||
@@ -48,7 +56,15 @@ describe("renderer/utils/StorageHelper", () => {
|
||||
},
|
||||
});
|
||||
|
||||
storageHelperAsync = new StorageHelper(storageKey, {
|
||||
storageHelperAsync = new StorageHelper({
|
||||
logger: {
|
||||
debug: noop,
|
||||
error: noop,
|
||||
info: noop,
|
||||
silly: noop,
|
||||
warn: noop,
|
||||
},
|
||||
}, storageKey, {
|
||||
autoInit: false,
|
||||
defaultValue: storageHelper.defaultValue,
|
||||
storage: {
|
||||
@@ -118,7 +134,15 @@ describe("renderer/utils/StorageHelper", () => {
|
||||
beforeEach(() => {
|
||||
observedChanges.length = 0;
|
||||
|
||||
storageHelper = new StorageHelper<typeof defaultValue>("some-key", {
|
||||
storageHelper = new StorageHelper<typeof defaultValue>({
|
||||
logger: {
|
||||
debug: noop,
|
||||
error: noop,
|
||||
info: noop,
|
||||
silly: noop,
|
||||
warn: noop,
|
||||
},
|
||||
}, "some-key", {
|
||||
autoInit: true,
|
||||
defaultValue,
|
||||
storage: {
|
||||
|
||||
+8
-10
@@ -3,22 +3,20 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../../../before-frame-starts/tokens";
|
||||
import listeningOnMessageChannelsInjectable from "../../../../common/utils/channel/listening-on-message-channels.injectable";
|
||||
|
||||
const startListeningOfChannelsInjectable = getInjectable({
|
||||
id: "start-listening-of-channels-renderer",
|
||||
|
||||
instantiate: (di) => {
|
||||
const listeningOfChannels = di.inject(listeningOnMessageChannelsInjectable);
|
||||
instantiate: (di) => ({
|
||||
id: "start-listening-of-channels-renderer",
|
||||
run: () => {
|
||||
const listeningOfChannels = di.inject(listeningOnMessageChannelsInjectable);
|
||||
|
||||
return {
|
||||
id: "start-listening-of-channels-renderer",
|
||||
run: async () => {
|
||||
await listeningOfChannels.start();
|
||||
},
|
||||
};
|
||||
},
|
||||
listeningOfChannels.start();
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
@@ -7,17 +7,19 @@
|
||||
// Because app creates random port between restarts => storage session wiped out each time.
|
||||
import { comparer, reaction, toJS, when } from "mobx";
|
||||
import type { StorageLayer } from "../storageHelper";
|
||||
import { StorageHelper } from "../storageHelper";
|
||||
import type { JsonObject, JsonValue } from "type-fest";
|
||||
import { storageHelperLogPrefix, StorageHelper } from "../storageHelper";
|
||||
import type { JsonObject } from "type-fest";
|
||||
import type { Logger } from "../../../common/logger";
|
||||
import type { JoinPaths } from "../../../common/path/join-paths.injectable";
|
||||
import type { WriteJson } from "../../../common/fs/write-json-file.injectable";
|
||||
import type { ReadJson } from "../../../common/fs/read-json-file.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
storage: { initialized: boolean; loaded: boolean; data: Record<string, any> };
|
||||
storage: { initialized: boolean; loaded: boolean; data: Partial<Record<string, unknown>> };
|
||||
logger: Logger;
|
||||
directoryForLensLocalStorage: string;
|
||||
readJsonFile: (filePath: string) => Promise<JsonValue>;
|
||||
writeJsonFile: (filePath: string, contentObject: JsonObject) => Promise<void>;
|
||||
readJsonFile: ReadJson;
|
||||
writeJsonFile: WriteJson;
|
||||
joinPaths: JoinPaths;
|
||||
hostedClusterId: string | undefined;
|
||||
saveDelay: number;
|
||||
@@ -37,9 +39,7 @@ export const createStorage = ({
|
||||
writeJsonFile,
|
||||
hostedClusterId,
|
||||
saveDelay,
|
||||
}: Dependencies): CreateStorage => (key, defaultValue) => {
|
||||
const { logPrefix } = StorageHelper;
|
||||
|
||||
}: Dependencies): CreateStorage => <T>(key: string, defaultValue: T) => {
|
||||
if (!storage.initialized) {
|
||||
storage.initialized = true;
|
||||
|
||||
@@ -51,7 +51,7 @@ export const createStorage = ({
|
||||
} catch {
|
||||
// do nothing
|
||||
} finally {
|
||||
logger.info(`${logPrefix} loading finished for ${filePath}`);
|
||||
logger.info(`${storageHelperLogPrefix} loading finished for ${filePath}`);
|
||||
storage.loaded = true;
|
||||
}
|
||||
|
||||
@@ -62,30 +62,32 @@ export const createStorage = ({
|
||||
});
|
||||
|
||||
async function saveFile(state: Record<string, any> = {}) {
|
||||
logger.info(`${logPrefix} saving ${filePath}`);
|
||||
logger.info(`${storageHelperLogPrefix} saving ${filePath}`);
|
||||
|
||||
try {
|
||||
await writeJsonFile(filePath, state);
|
||||
} catch (error) {
|
||||
logger.error(`${logPrefix} saving failed: ${error}`, {
|
||||
logger.error(`${storageHelperLogPrefix} saving failed: ${error}`, {
|
||||
json: state, jsonFilePath: filePath,
|
||||
});
|
||||
}
|
||||
}
|
||||
})()
|
||||
.catch(error => logger.error(`${logPrefix} Failed to initialize storage: ${error}`));
|
||||
.catch(error => logger.error(`${storageHelperLogPrefix} Failed to initialize storage: ${error}`));
|
||||
}
|
||||
|
||||
return new StorageHelper(key, {
|
||||
return new StorageHelper({
|
||||
logger,
|
||||
}, key, {
|
||||
autoInit: true,
|
||||
defaultValue,
|
||||
storage: {
|
||||
async getItem(key: string) {
|
||||
await when(() => storage.loaded);
|
||||
|
||||
return storage.data[key];
|
||||
return storage.data[key] as T;
|
||||
},
|
||||
setItem(key: string, value: any) {
|
||||
setItem(key: string, value: T) {
|
||||
storage.data[key] = value;
|
||||
},
|
||||
removeItem(key: string) {
|
||||
|
||||
@@ -8,8 +8,8 @@ import { action, comparer, computed, makeObservable, observable, observe, toJS,
|
||||
import type { Draft } from "immer";
|
||||
import { produce, isDraft } from "immer";
|
||||
import { isEqual, isPlainObject } from "lodash";
|
||||
import logger from "../../main/logger";
|
||||
import assert from "assert";
|
||||
import type { Logger } from "../../common/logger";
|
||||
|
||||
export interface StorageChange<T> {
|
||||
key: string;
|
||||
@@ -26,9 +26,9 @@ export interface StorageAdapter<T> {
|
||||
}
|
||||
|
||||
export interface StorageHelperOptions<T> {
|
||||
autoInit?: boolean; // start preloading data immediately, default: true
|
||||
storage: StorageAdapter<T>;
|
||||
defaultValue: T;
|
||||
readonly autoInit?: boolean; // start preloading data immediately, default: true
|
||||
readonly storage: StorageAdapter<T>;
|
||||
readonly defaultValue: T;
|
||||
}
|
||||
|
||||
export interface StorageLayer<T> {
|
||||
@@ -41,11 +41,16 @@ export interface StorageLayer<T> {
|
||||
merge(value: Partial<T> | ((draft: Draft<T>) => Partial<T> | void)): void;
|
||||
}
|
||||
|
||||
export const storageHelperLogPrefix = "[STORAGE-HELPER]:";
|
||||
|
||||
interface Dependencies {
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
export class StorageHelper<T> implements StorageLayer<T> {
|
||||
static logPrefix = "[StorageHelper]:";
|
||||
readonly storage: StorageAdapter<T>;
|
||||
|
||||
private data = observable.box<T | undefined>(undefined, {
|
||||
private readonly data = observable.box<T | undefined>(undefined, {
|
||||
deep: true,
|
||||
equals: comparer.structural,
|
||||
});
|
||||
@@ -61,7 +66,7 @@ export class StorageHelper<T> implements StorageLayer<T> {
|
||||
return this.options.defaultValue;
|
||||
}
|
||||
|
||||
constructor(readonly key: string, private options: StorageHelperOptions<T>) {
|
||||
constructor(private readonly dependencies: Dependencies, readonly key: string, private readonly options: StorageHelperOptions<T>) {
|
||||
makeObservable(this);
|
||||
|
||||
const { storage, autoInit = true } = options;
|
||||
@@ -89,7 +94,7 @@ export class StorageHelper<T> implements StorageLayer<T> {
|
||||
};
|
||||
|
||||
private onError = (error: any): void => {
|
||||
logger.error(`${StorageHelper.logPrefix} loading error: ${error}`, this);
|
||||
this.dependencies.logger.error(`${storageHelperLogPrefix} loading error: ${error}`, this);
|
||||
};
|
||||
|
||||
@action
|
||||
@@ -127,7 +132,7 @@ export class StorageHelper<T> implements StorageLayer<T> {
|
||||
|
||||
this.storage.onChange?.({ value, oldValue, key: this.key });
|
||||
} catch (error) {
|
||||
logger.error(`${StorageHelper.logPrefix} updating storage: ${error}`, this, { value, oldValue });
|
||||
this.dependencies.logger.error(`${storageHelperLogPrefix} updating storage: ${error}`, this, { value, oldValue });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,43 +3,34 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/tokens";
|
||||
import { syncBoxInitialValueChannel } from "../../../common/utils/sync-box/channels";
|
||||
import createSyncBoxStateInjectable from "../../../common/utils/sync-box/sync-box-state.injectable";
|
||||
import { requestFromChannelInjectionToken } from "../../../common/utils/channel/request-from-channel-injection-token";
|
||||
import { runInAction } from "mobx";
|
||||
import type { SyncBox } from "../../../common/utils/sync-box/sync-box-injection-token";
|
||||
import { syncBoxInjectionToken } from "../../../common/utils/sync-box/sync-box-injection-token";
|
||||
import assert from "assert";
|
||||
|
||||
const provideInitialValuesForSyncBoxesInjectable = getInjectable({
|
||||
id: "provide-initial-values-for-sync-boxes",
|
||||
|
||||
instantiate: (di) => {
|
||||
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||
instantiate: (di) => ({
|
||||
id: "provide-initial-values-for-sync-boxes",
|
||||
run: async () => {
|
||||
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||
const syncBoxes = di.injectMany(syncBoxInjectionToken);
|
||||
const initialValues = await requestFromChannel(syncBoxInitialValueChannel);
|
||||
|
||||
const syncBoxes = di.injectMany(syncBoxInjectionToken);
|
||||
runInAction(() => {
|
||||
for (const { id, value } of initialValues) {
|
||||
const syncBox = syncBoxes.find((box) => box.id === id);
|
||||
|
||||
const setSyncBoxState = (syncBox: SyncBox<any>, state: any) =>
|
||||
di.inject(createSyncBoxStateInjectable, syncBox.id).set(state);
|
||||
|
||||
return {
|
||||
id: "provide-initial-values-for-sync-boxes",
|
||||
run: async () => {
|
||||
const initialValues = await requestFromChannel(syncBoxInitialValueChannel);
|
||||
|
||||
runInAction(() => {
|
||||
initialValues.forEach(({ id, value }) => {
|
||||
const syncBox = syncBoxes.find((box) => box.id === id);
|
||||
|
||||
assert(syncBox);
|
||||
|
||||
setSyncBoxState(syncBox, value);
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
assert(syncBox);
|
||||
di.inject(createSyncBoxStateInjectable, syncBox.id).set(value);
|
||||
}
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/tokens";
|
||||
import buildVersionInjectable from "./build-version.injectable";
|
||||
|
||||
const initializeBuildVersionInjectable = getInjectable({
|
||||
id: "initialize-build-version",
|
||||
instantiate: (di) => {
|
||||
const buildVersion = di.inject(buildVersionInjectable);
|
||||
instantiate: (di) => ({
|
||||
id: "initialize-build-version",
|
||||
run: async () => {
|
||||
const buildVersion = di.inject(buildVersionInjectable);
|
||||
|
||||
return {
|
||||
id: "initialize-build-version",
|
||||
run: () => buildVersion.init(),
|
||||
};
|
||||
},
|
||||
await buildVersion.init();
|
||||
},
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/tokens";
|
||||
import initReleaseChannelInjectable from "../release-channel/init.injectable";
|
||||
import defaultUpdateChannelInjectable from "../../../features/application-update/common/selected-update-channel/default-update-channel.injectable";
|
||||
|
||||
const initDefaultUpdateChannelInjectable = getInjectable({
|
||||
id: "init-default-update-channel",
|
||||
instantiate: (di) => {
|
||||
const defaultUpdateChannel = di.inject(defaultUpdateChannelInjectable);
|
||||
instantiate: (di) => ({
|
||||
id: "init-default-update-channel",
|
||||
run: async () => {
|
||||
const defaultUpdateChannel = di.inject(defaultUpdateChannelInjectable);
|
||||
|
||||
return {
|
||||
id: "init-default-update-channel",
|
||||
run: () => defaultUpdateChannel.init(),
|
||||
runAfter: di.inject(initReleaseChannelInjectable),
|
||||
};
|
||||
},
|
||||
await defaultUpdateChannel.init();
|
||||
},
|
||||
runAfter: di.inject(initReleaseChannelInjectable),
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
|
||||
@@ -4,20 +4,20 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import releaseChannelInjectable from "../../../common/vars/release-channel.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/tokens";
|
||||
import initSemanticBuildVersionInjectable from "../semantic-build-version/init.injectable";
|
||||
|
||||
const initReleaseChannelInjectable = getInjectable({
|
||||
id: "init-release-channel",
|
||||
instantiate: (di) => {
|
||||
const releaseChannel = di.inject(releaseChannelInjectable);
|
||||
instantiate: (di) => ({
|
||||
id: "init-release-channel",
|
||||
run: async () => {
|
||||
const releaseChannel = di.inject(releaseChannelInjectable);
|
||||
|
||||
return {
|
||||
id: "init-release-channel",
|
||||
run: () => releaseChannel.init(),
|
||||
runAfter: di.inject(initSemanticBuildVersionInjectable),
|
||||
};
|
||||
},
|
||||
await releaseChannel.init();
|
||||
},
|
||||
runAfter: di.inject(initSemanticBuildVersionInjectable),
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
|
||||
@@ -4,20 +4,20 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import buildSemanticVersionInjectable from "../../../common/vars/build-semantic-version.injectable";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/tokens";
|
||||
import initializeBuildVersionInjectable from "../build-version/init.injectable";
|
||||
|
||||
const initSemanticBuildVersionInjectable = getInjectable({
|
||||
id: "init-semantic-build-version",
|
||||
instantiate: (di) => {
|
||||
const buildSemanticVersion = di.inject(buildSemanticVersionInjectable);
|
||||
instantiate: (di) => ({
|
||||
id: "init-semantic-build-version",
|
||||
run: async () => {
|
||||
const buildSemanticVersion = di.inject(buildSemanticVersionInjectable);
|
||||
|
||||
return {
|
||||
id: "init-semantic-build-version",
|
||||
run: () => buildSemanticVersion.init(),
|
||||
runAfter: di.inject(initializeBuildVersionInjectable),
|
||||
};
|
||||
},
|
||||
await buildSemanticVersion.init();
|
||||
},
|
||||
runAfter: di.inject(initializeBuildVersionInjectable),
|
||||
}),
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user