Remove BaseStore<T> and replace with composition of dependencies (#7002)

* Rename ExtensionStore -> BaseExtensionStore
- The name was too close to ExtensionsStore

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Move ExtensionsStore to new format

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Move ClusterStore to new format

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Move UserStore to new format

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Cleanup types to remove multiple cast locations

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Move HotbarStore to new format

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Move WeblinkStore to new format

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Move FileSystemProvisionerStore to new format

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Update snapshots

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Clean up impl and rename to better describe intent

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix remaining type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fully split apart the enabled extensions storage

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fully split apart the clusters storage

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fully split apart the hotbar storage

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fully split apart the weblinks storage

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fully split apart the user preferences storage

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix crashing

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix tests and snapshots

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix integration test failures

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Improve typing to prevent errors in the future.

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Cleanup @k8slens/messaging and friends

- To fix type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix lint issue

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix global override not being complete enough causing tests to fail

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Bump memory for unit tests on CI

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Attempt to fix memory issue on CI again

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fixup test because of new injectables

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Upgrade Jest

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix unit tests falling over

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Back out jest config change

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove console log

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Update snapshot

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix tests by matching equality instead of snapshots

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix tests by forcing specific snapshot style

- Ubuntu CI seems to format arrays in snapshots differently than macOS locally

Signed-off-by: Sebastian Malton <sebastian@malton.name>

---------

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton authored and GitHub committed 2023-03-28 17:54:25 +03:00
1 parent ba4a283af9
commit 49f0a1af9c
365 files changed
+6733 -3972

No files matched your search

@@ -3,12 +3,12 @@
* 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";
import { shouldPersistentStorageDisableSyncInIpcListenerInjectionToken } from "../../common/persistent-storage/disable-sync";
const shouldBaseStoreDisableSyncInIpcListenerInjectable = getInjectable({
id: "should-base-store-disable-sync-in-ipc-listener",
instantiate: () => false,
injectionToken: shouldBaseStoreDisableSyncInIpcListenerInjectionToken,
injectionToken: shouldPersistentStorageDisableSyncInIpcListenerInjectionToken,
});
export default shouldBaseStoreDisableSyncInIpcListenerInjectable;
@@ -3,7 +3,7 @@
* 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";
import { persistentStorageIpcChannelPrefixesInjectionToken } from "../../common/persistent-storage/channel-prefix";
const baseStoreIpcChannelPrefixInjectable = getInjectable({
id: "base-store-ipc-channel-prefix",
@@ -11,7 +11,7 @@ const baseStoreIpcChannelPrefixInjectable = getInjectable({
local: "store-sync-main",
remote: "store-sync-renderer",
}),
injectionToken: baseStoreIpcChannelPrefixesInjectionToken,
injectionToken: persistentStorageIpcChannelPrefixesInjectionToken,
});
export default baseStoreIpcChannelPrefixInjectable;
@@ -3,7 +3,7 @@
* 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 { persistStateToConfigInjectionToken } from "../../common/persistent-storage/save-to-file";
import loggerInjectable from "../../common/logger.injectable";
const persistStateToConfigInjectable = getInjectable({
@@ -17,9 +17,6 @@ import type { ConfigToModels } from "../kubeconfig-sync/config-to-models.injecta
import configToModelsInjectable from "../kubeconfig-sync/config-to-models.injectable";
import kubeconfigSyncManagerInjectable from "../kubeconfig-sync/manager.injectable";
import type { KubeconfigSyncManager } from "../kubeconfig-sync/manager";
import type { KubeconfigSyncValue } from "../../../common/user-store";
import kubeconfigSyncsInjectable from "../../../common/user-store/kubeconfig-syncs.injectable";
import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import type { AsyncFnMock } from "@async-fn/jest";
import type { Stat } from "../../../common/fs/stat.injectable";
@@ -36,12 +33,13 @@ import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable
import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable";
import type { KubeconfigManager } from "../../kubeconfig-manager/kubeconfig-manager";
import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable";
import type { KubeconfigSyncValue } from "../../../features/user-preferences/common/preferences-helpers";
import kubeconfigSyncsInjectable from "../../../features/user-preferences/common/kubeconfig-syncs.injectable";
describe("kubeconfig-sync.source tests", () => {
let computeKubeconfigDiff: ComputeKubeconfigDiff;
let configToModels: ConfigToModels;
let kubeconfigSyncs: ObservableMap<string, KubeconfigSyncValue>;
let clusters: Map<string, Cluster>;
let di: DiContainer;
beforeEach(async () => {
@@ -58,9 +56,6 @@ describe("kubeconfig-sync.source tests", () => {
ensurePath: async () => "/some-proxy-kubeconfig-file",
} as Partial<KubeconfigManager> as KubeconfigManager));
clusters = new Map();
di.override(getClusterByIdInjectable, () => id => clusters.get(id));
kubeconfigSyncs = observable.map();
di.override(kubeconfigSyncsInjectable, () => kubeconfigSyncs);
@@ -1,6 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export { syncWeblinks } from "./weblinks";
@@ -9,7 +9,6 @@ import { action } from "mobx";
import { homedir } from "os";
import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
import type { CatalogEntity } from "../../../common/catalog";
import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable";
import { Cluster } from "../../../common/cluster/cluster";
import { loadConfigFromString } from "../../../common/kube-helpers";
import clustersThatAreBeingDeletedInjectable from "../../cluster/are-being-deleted.injectable";
@@ -17,6 +16,7 @@ import { catalogEntityFromCluster } from "../../cluster/manager";
import configToModelsInjectable from "./config-to-models.injectable";
import kubeconfigSyncLoggerInjectable from "./logger.injectable";
import clusterConnectionInjectable from "../../cluster/cluster-connection.injectable";
import getClusterByIdInjectable from "../../../features/cluster/storage/common/get-by-id.injectable";
export type ComputeKubeconfigDiff = (contents: string, source: ObservableMap<string, [Cluster, CatalogEntity]>, filePath: string) => void;
@@ -7,7 +7,7 @@ import directoryForKubeConfigsInjectable from "../../../common/app-paths/directo
import { KubeconfigSyncManager } from "./manager";
import kubeconfigSyncLoggerInjectable from "./logger.injectable";
import watchKubeconfigFileChangesInjectable from "./watch-file-changes.injectable";
import kubeconfigSyncsInjectable from "../../../common/user-store/kubeconfig-syncs.injectable";
import kubeconfigSyncsInjectable from "../../../features/user-preferences/common/kubeconfig-syncs.injectable";
const kubeconfigSyncManagerInjectable = getInjectable({
id: "kubeconfig-sync-manager",
@@ -8,9 +8,9 @@ import { action, observable, computed, makeObservable, observe } from "mobx";
import type { CatalogEntity } from "../../../common/catalog";
import type { Disposer } from "@k8slens/utilities";
import { iter } from "@k8slens/utilities";
import type { KubeconfigSyncValue } from "../../../common/user-store";
import type { Logger } from "../../../common/logger";
import type { WatchKubeconfigFileChanges } from "./watch-file-changes.injectable";
import type { KubeconfigSyncValue } from "../../../features/user-preferences/common/preferences-helpers";
interface KubeconfigSyncManagerDependencies {
readonly directoryForKubeConfigs: string;
@@ -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 { syncWeblinks } from "./weblinks";
import weblinkStoreInjectable from "../../common/weblinks-store/weblink-store.injectable";
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
const syncWeblinksInjectable = getInjectable({
id: "sync-weblinks",
instantiate: (di) => syncWeblinks({
weblinkStore: di.inject(weblinkStoreInjectable),
catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable),
}),
});
export default syncWeblinksInjectable;
@@ -1,93 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { computed, observable, reaction } from "mobx";
import type { WeblinkStore } from "../../common/weblinks-store/weblink-store";
import { WebLink } from "../../common/catalog-entities";
import type { CatalogEntityRegistry } from "../catalog";
import got from "got";
import type { Disposer } from "@k8slens/utilities";
import { random } from "lodash";
async function validateLink(link: WebLink) {
try {
const response = await got.get(link.spec.url, {
throwHttpErrors: false,
timeout: 20_000,
});
if (response.statusCode >= 200 && response.statusCode < 500) {
link.status.phase = "available";
} else {
link.status.phase = "unavailable";
}
} catch {
link.status.phase = "unavailable";
}
}
interface Dependencies {
weblinkStore: WeblinkStore;
catalogEntityRegistry: CatalogEntityRegistry;
}
export const syncWeblinks = ({ weblinkStore, catalogEntityRegistry }: Dependencies) => () => {
const webLinkEntities = observable.map<string, [WebLink, Disposer]>();
function periodicallyCheckLink(link: WebLink): Disposer {
validateLink(link);
let interval: NodeJS.Timeout;
const timeout = setTimeout(() => {
interval = setInterval(() => validateLink(link), 60 * 60 * 1000); // every 60 minutes
}, random(0, 5 * 60 * 1000, false)); // spread out over 5 minutes
return () => {
clearTimeout(timeout);
clearInterval(interval);
};
}
reaction(() => weblinkStore.weblinks, (links) => {
const seenWeblinks = new Set<string>();
for (const weblinkData of links) {
seenWeblinks.add(weblinkData.id);
if (!webLinkEntities.has(weblinkData.id)) {
const link = new WebLink({
metadata: {
uid: weblinkData.id,
name: weblinkData.name,
source: "local",
labels: {},
},
spec: {
url: weblinkData.url,
},
status: {
phase: "available",
active: true,
},
});
webLinkEntities.set(weblinkData.id, [
link,
periodicallyCheckLink(link),
]);
}
}
// Stop checking and remove weblinks that are no longer in the store
for (const [weblinkId, [, disposer]] of webLinkEntities) {
if (!seenWeblinks.has(weblinkId)) {
disposer();
webLinkEntities.delete(weblinkId);
}
}
}, { fireImmediately: true });
catalogEntityRegistry.addComputedSource("weblinks", computed(() => Array.from(webLinkEntities.values(), ([link]) => link)));
};
@@ -3,8 +3,10 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import clusterStoreInjectable from "../../common/cluster-store/cluster-store.injectable";
import loggerInjectable from "../../common/logger.injectable";
import addClusterInjectable from "../../features/cluster/storage/common/add.injectable";
import clustersInjectable from "../../features/cluster/storage/common/clusters.injectable";
import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable";
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
import clustersThatAreBeingDeletedInjectable from "./are-being-deleted.injectable";
import clusterConnectionInjectable from "./cluster-connection.injectable";
@@ -17,11 +19,13 @@ const clusterManagerInjectable = getInjectable({
id: "cluster-manager",
instantiate: (di) => new ClusterManager({
store: di.inject(clusterStoreInjectable),
catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable),
clustersThatAreBeingDeleted: di.inject(clustersThatAreBeingDeletedInjectable),
visibleCluster: di.inject(visibleClusterInjectable),
logger: di.inject(loggerInjectable),
addCluster: di.inject(addClusterInjectable),
clusters: di.inject(clustersInjectable),
getClusterById: di.inject(getClusterByIdInjectable),
updateEntityMetadata: di.inject(updateEntityMetadataInjectable),
updateEntitySpec: di.inject(updateEntitySpecInjectable),
getClusterConnection: (cluster) => di.inject(clusterConnectionInjectable, cluster),
+19 -12
View File
@@ -4,34 +4,37 @@
*/
import "../../common/ipc/cluster";
import type { IObservableValue, ObservableSet } from "mobx";
import type { IComputedValue, IObservableValue, ObservableSet } from "mobx";
import { action, makeObservable, observe, reaction, toJS } from "mobx";
import type { Cluster } from "../../common/cluster/cluster";
import { isErrnoException } from "@k8slens/utilities";
import { isKubernetesCluster, KubernetesCluster, LensKubernetesClusterStatus } from "../../common/catalog-entities/kubernetes-cluster";
import { ipcMainOn } from "../../common/ipc";
import { once } from "lodash";
import type { ClusterStore } from "../../common/cluster-store/cluster-store";
import type { ClusterId } from "../../common/cluster-types";
import type { CatalogEntityRegistry } from "../catalog";
import type { Logger } from "../../common/logger";
import type { UpdateEntityMetadata } from "./update-entity-metadata.injectable";
import type { UpdateEntitySpec } from "./update-entity-spec.injectable";
import type { ClusterConnection } from "./cluster-connection.injectable";
import type { GetClusterById } from "../../features/cluster/storage/common/get-by-id.injectable";
import type { AddCluster } from "../../features/cluster/storage/common/add.injectable";
const logPrefix = "[CLUSTER-MANAGER]:";
const lensSpecificClusterStatuses: Set<string> = new Set(Object.values(LensKubernetesClusterStatus));
interface Dependencies {
readonly store: ClusterStore;
readonly catalogEntityRegistry: CatalogEntityRegistry;
readonly clustersThatAreBeingDeleted: ObservableSet<ClusterId>;
readonly visibleCluster: IObservableValue<ClusterId | null>;
readonly logger: Logger;
readonly clusters: IComputedValue<Cluster[]>;
updateEntityMetadata: UpdateEntityMetadata;
updateEntitySpec: UpdateEntitySpec;
getClusterConnection: (cluster: Cluster) => ClusterConnection;
getClusterById: GetClusterById;
addCluster: AddCluster;
}
export class ClusterManager {
@@ -42,15 +45,15 @@ export class ClusterManager {
init = once(() => {
// reacting to every cluster's state change and total amount of items
reaction(
() => this.dependencies.store.clustersList.map(c => c.getState()),
() => this.updateCatalog(this.dependencies.store.clustersList),
() => this.dependencies.clusters.get().map(c => c.getState()),
() => this.updateCatalog(this.dependencies.clusters.get()),
{ fireImmediately: false },
);
// reacting to every cluster's preferences change and total amount of items
reaction(
() => this.dependencies.store.clustersList.map(c => toJS(c.preferences)),
() => this.updateCatalog(this.dependencies.store.clustersList),
() => this.dependencies.clusters.get().map(c => toJS(c.preferences)),
() => this.updateCatalog(this.dependencies.clusters.get()),
{ fireImmediately: false },
);
@@ -152,7 +155,7 @@ export class ClusterManager {
@action
protected syncClustersFromCatalog(entities: KubernetesCluster[]) {
for (const entity of entities) {
const cluster = this.dependencies.store.getById(entity.getId());
const cluster = this.dependencies.getClusterById(entity.getId());
if (!cluster) {
const model = {
@@ -167,7 +170,7 @@ export class ClusterManager {
* Add the bare minimum of data to ClusterStore. And especially no
* preferences, as those might be configured by the entity's source
*/
this.dependencies.store.addCluster(model);
this.dependencies.addCluster(model);
} catch (error) {
if (isErrnoException(error) && error.code === "ENOENT" && error.path === entity.spec.kubeconfigPath) {
this.dependencies.logger.warn(`${logPrefix} kubeconfig file disappeared`, model);
@@ -208,7 +211,9 @@ export class ClusterManager {
this.dependencies.logger.info(`${logPrefix} network is offline`);
await Promise.allSettled(
this.dependencies.store.clustersList
this.dependencies
.clusters
.get()
.filter(cluster => !cluster.disconnected.get())
.map(async (cluster) => {
cluster.online.set(false);
@@ -225,7 +230,9 @@ export class ClusterManager {
this.dependencies.logger.info(`${logPrefix} network is online`);
await Promise.allSettled(
this.dependencies.store.clustersList
this.dependencies
.clusters
.get()
.filter(cluster => !cluster.disconnected.get())
.map((cluster) => (
this.dependencies
@@ -236,7 +243,7 @@ export class ClusterManager {
};
stop() {
for (const cluster of this.dependencies.store.clustersList) {
for (const cluster of this.dependencies.clusters.get()) {
this.dependencies
.getClusterConnection(cluster)
.disconnect();
@@ -18,7 +18,7 @@ interface Pre360ClusterModel extends ClusterModel {
}
import { getInjectable } from "@ogre-tools/injectable";
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
import { clusterStoreMigrationInjectionToken } from "../../../features/cluster/storage/common/migration-token";
import readFileBufferSyncInjectable from "../../../common/fs/read-file-buffer-sync.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import writeFileSyncInjectable from "../../../common/fs/write-file-sync.injectable";
@@ -4,7 +4,7 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
import { clusterStoreMigrationInjectionToken } from "../../../features/cluster/storage/common/migration-token";
import type { ClusterModel } from "../../../common/cluster-types";
import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
@@ -10,7 +10,7 @@ import { isDefined } from "@k8slens/utilities";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import { getInjectable } from "@ogre-tools/injectable";
import loggerInjectable from "../../../common/logger.injectable";
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
import { clusterStoreMigrationInjectionToken } from "../../../features/cluster/storage/common/migration-token";
import { generateNewIdFor } from "../../../common/utils/generate-new-id-for";
interface Pre500ClusterModel extends ClusterModel {
@@ -6,7 +6,7 @@
// Fix embedded kubeconfig paths under snap config
import { getInjectable } from "@ogre-tools/injectable";
import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token";
import { clusterStoreMigrationInjectionToken } from "../../../features/cluster/storage/common/migration-token";
import loggerInjectable from "../../../common/logger.injectable";
import isSnapPackageInjectable from "../../../common/vars/is-snap-package.injectable";
import type { ClusterModel } from "../../../common/cluster-types";
@@ -4,7 +4,7 @@
*/
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
import { computed } from "mobx";
import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
import { shouldShowResourceInjectionToken } from "../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token";
import type { KubeApiResourceDescriptor } from "../../common/rbac";
import { formatKubeApiResource } from "../../common/rbac";
@@ -5,12 +5,12 @@
import { getInjectable } from "@ogre-tools/injectable";
import { setupIpcMainHandlers } from "./setup-ipc-main-handlers";
import loggerInjectable from "../../../../common/logger.injectable";
import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable";
import { onLoadOfApplicationInjectionToken } from "@k8slens/application";
import applicationMenuItemCompositeInjectable from "../../../../features/application-menu/main/application-menu-item-composite.injectable";
import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable";
import pushCatalogToRendererInjectable from "../../../catalog-sync-to-renderer/push-catalog-to-renderer.injectable";
import clusterFramesInjectable from "../../../../common/cluster-frames.injectable";
import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable";
import clustersInjectable from "../../../../features/cluster/storage/common/clusters.injectable";
const setupIpcMainHandlersInjectable = getInjectable({
id: "setup-ipc-main-handlers",
@@ -24,7 +24,7 @@ const setupIpcMainHandlersInjectable = getInjectable({
setupIpcMainHandlers({
applicationMenuItemComposite: di.inject(applicationMenuItemCompositeInjectable),
pushCatalogToRenderer: di.inject(pushCatalogToRendererInjectable),
clusterStore: di.inject(clusterStoreInjectable),
clusters: di.inject(clustersInjectable),
getClusterById: di.inject(getClusterByIdInjectable),
clusterFrames: di.inject(clusterFramesInjectable),
});
@@ -7,7 +7,6 @@ import { BrowserWindow, Menu } from "electron";
import type { ClusterFrameInfo } from "../../../../common/cluster-frames.injectable";
import { clusterSetFrameIdHandler, clusterStates } from "../../../../common/ipc/cluster";
import type { ClusterId } from "../../../../common/cluster-types";
import type { ClusterStore } from "../../../../common/cluster-store/cluster-store";
import { broadcastMainChannel, broadcastMessage, ipcMainHandle, ipcMainOn } from "../../../../common/ipc";
import type { IComputedValue, ObservableMap } from "mobx";
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../../common/ipc/window";
@@ -16,21 +15,23 @@ import type { ApplicationMenuItemTypes } from "../../../../features/application-
import type { Composite } from "../../../../common/utils/composite/get-composite/get-composite";
import { getApplicationMenuTemplate } from "../../../../features/application-menu/main/populate-application-menu.injectable";
import type { MenuItemRoot } from "../../../../features/application-menu/main/application-menu-item-composite.injectable";
import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable";
import type { GetClusterById } from "../../../../features/cluster/storage/common/get-by-id.injectable";
import type { Cluster } from "../../../../common/cluster/cluster";
interface Dependencies {
applicationMenuItemComposite: IComputedValue<Composite<ApplicationMenuItemTypes | MenuItemRoot>>;
clusterStore: ClusterStore;
getClusterById: GetClusterById;
pushCatalogToRenderer: () => void;
clusterFrames: ObservableMap<string, ClusterFrameInfo>;
clusters: IComputedValue<Cluster[]>;
}
export const setupIpcMainHandlers = ({
applicationMenuItemComposite,
clusterStore,
getClusterById,
pushCatalogToRenderer,
clusterFrames,
clusters,
}: Dependencies) => {
ipcMainHandle(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => {
const cluster = getClusterById(clusterId);
@@ -60,7 +61,7 @@ export const setupIpcMainHandlers = ({
});
ipcMainHandle(clusterStates, () => (
clusterStore.clustersList.map(cluster => ({
clusters.get().map(cluster => ({
id: cluster.id,
state: cluster.getState(),
}))
@@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import type { Writable } from "type-fest";
import loggerInjectable from "../../common/logger.injectable";
import { createExtensionInstanceInjectionToken } from "../../extensions/extension-loader/create-extension-instance.token";
import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
import ensureHashedDirectoryForExtensionInjectable from "../../extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
import { lensExtensionDependencies } from "../../extensions/lens-extension";
import type { LensMainExtensionDependencies } from "../../extensions/lens-extension-set-dependencies";
import type { LensMainExtension } from "../../extensions/lens-main-extension";
@@ -17,7 +17,7 @@ const createExtensionInstanceInjectable = getInjectable({
id: "create-extension-instance",
instantiate: (di) => {
const deps: LensMainExtensionDependencies = {
fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable),
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
entityRegistry: di.inject(catalogEntityRegistryInjectable),
navigate: di.inject(navigateForExtensionInjectable),
logger: di.inject(loggerInjectable),
@@ -10,7 +10,7 @@ import spawnInjectable from "./child-process/spawn.injectable";
import initializeExtensionsInjectable from "./start-main-application/runnables/initialize-extensions.injectable";
import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable";
import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable";
import setupSyncingOfWeblinksInjectable from "./start-main-application/runnables/setup-syncing-of-weblinks.injectable";
import setupSyncingOfWeblinksInjectable from "../features/weblinks/main/setup-syncing-of-weblinks.injectable";
import setupDeepLinkingInjectable from "./electron-app/runnables/setup-deep-linking.injectable";
import setupMainWindowVisibilityAfterActivationInjectable from "./electron-app/runnables/setup-main-window-visibility-after-activation.injectable";
import setupDeviceShutdownInjectable from "./electron-app/runnables/setup-device-shutdown.injectable";
@@ -4,7 +4,7 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import httpsProxyConfigurationInjectable from "../../../common/user-store/https-proxy.injectable";
import httpsProxyConfigurationInjectable from "../../../features/user-preferences/common/https-proxy.injectable";
const execHelmEnvInjectable = getInjectable({
id: "exec-helm-env",
@@ -1,34 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// Cleans up a store that had the state related data stored
import { getEmptyHotbar } from "../../../common/hotbars/types";
import catalogCatalogEntityInjectable from "../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token";
const v500Alpha0HotbarStoreMigrationInjectable = getInjectable({
id: "v5.0.0-alpha.0-hotbar-store-migration",
instantiate: (di) => {
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
return {
version: "5.0.0-alpha.0",
run(store) {
const hotbar = getEmptyHotbar("default");
const { metadata: { uid, name, source }} = catalogCatalogEntity;
hotbar.items[0] = { entity: { uid, name, source }};
store.set("hotbars", [hotbar]);
},
};
},
injectionToken: hotbarStoreMigrationInjectionToken,
});
export default v500Alpha0HotbarStoreMigrationInjectable;
@@ -1,30 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// Cleans up a store that had the state related data stored
import type { Hotbar } from "../../../common/hotbars/types";
import * as uuid from "uuid";
import { getInjectable } from "@ogre-tools/injectable";
import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token";
const v500Alpha2HotbarStoreMigrationInjectable = getInjectable({
id: "v5.0.0-alpha.2-hotbar-store-migration",
instantiate: () => ({
version: "5.0.0-alpha.2",
run(store) {
const rawHotbars = store.get("hotbars");
const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars : [];
store.set("hotbars", hotbars.map(({ id, ...rest }) => ({
id: id || uuid.v4(),
...rest,
})));
},
}),
injectionToken: hotbarStoreMigrationInjectionToken,
});
export default v500Alpha2HotbarStoreMigrationInjectable;
@@ -1,182 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import * as uuid from "uuid";
import type { Hotbar, HotbarItem } from "../../../common/hotbars/types";
import { defaultHotbarCells, getEmptyHotbar } from "../../../common/hotbars/types";
import { getLegacyGlobalDiForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import catalogCatalogEntityInjectable from "../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
import { isDefined, isErrnoException } from "@k8slens/utilities";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token";
import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import { generateNewIdFor } from "../../../common/utils/generate-new-id-for";
import type { ClusterModel } from "../../../common/cluster-types";
interface Pre500WorkspaceStoreModel {
workspaces: {
id: string;
name: string;
}[];
}
interface PartialHotbar {
id: string;
name: string;
items: (null | HotbarItem)[];
}
interface Pre500ClusterModel extends ClusterModel {
workspace?: string;
workspaces?: string[];
}
interface Pre500ClusterStoreModel {
clusters?: Pre500ClusterModel[];
}
const v500Beta10HotbarStoreMigrationInjectable = getInjectable({
id: "v5.0.0-beta.10-hotbar-store-migration",
instantiate: (di) => {
const userDataPath = di.inject(directoryForUserDataInjectable);
const joinPaths = di.inject(joinPathsInjectable);
const readJsonSync = di.inject(readJsonSyncInjectable);
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
const logger = di.inject(loggerInjectable);
return {
version: "5.0.0-beta.10",
run(store) {
const rawHotbars = store.get("hotbars");
const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars.filter(h => h && typeof h === "object") : [];
// Hotbars might be empty, if some of the previous migrations weren't run
if (hotbars.length === 0) {
const hotbar = getEmptyHotbar("default");
const { metadata: { uid, name, source }} = catalogCatalogEntity;
hotbar.items[0] = { entity: { uid, name, source }};
hotbars.push(hotbar);
}
try {
const workspaceStoreData: Pre500WorkspaceStoreModel = readJsonSync(joinPaths(userDataPath, "lens-workspace-store.json"));
const { clusters = [] }: Pre500ClusterStoreModel = readJsonSync(joinPaths(userDataPath, "lens-cluster-store.json"));
const workspaceHotbars = new Map<string, PartialHotbar>(); // mapping from WorkspaceId to HotBar
for (const { id, name } of workspaceStoreData.workspaces) {
logger.info(`Creating new hotbar for ${name}`);
workspaceHotbars.set(id, {
id: uuid.v4(), // don't use the old IDs as they aren't necessarily UUIDs
items: [],
name: `Workspace: ${name}`,
});
}
{
// grab the default named hotbar or the first.
const defaultHotbarIndex = Math.max(0, hotbars.findIndex(hotbar => hotbar.name === "default"));
const [{ name, id, items }] = hotbars.splice(defaultHotbarIndex, 1);
workspaceHotbars.set("default", {
name,
id,
items: items.filter(isDefined),
});
}
for (const cluster of clusters) {
const uid = generateNewIdFor(cluster);
for (const workspaceId of cluster.workspaces ?? [cluster.workspace].filter(isDefined)) {
const workspaceHotbar = workspaceHotbars.get(workspaceId);
if (!workspaceHotbar) {
logger.info(`Cluster ${uid} has unknown workspace ID, skipping`);
continue;
}
logger.info(`Adding cluster ${uid} to ${workspaceHotbar.name}`);
if (workspaceHotbar?.items.length < defaultHotbarCells) {
workspaceHotbar.items.push({
entity: {
uid: generateNewIdFor(cluster),
name: cluster.preferences?.clusterName || cluster.contextName,
},
});
}
}
}
for (const hotbar of workspaceHotbars.values()) {
if (hotbar.items.length === 0) {
logger.info(`Skipping ${hotbar.name} due to it being empty`);
continue;
}
while (hotbar.items.length < defaultHotbarCells) {
hotbar.items.push(null);
}
hotbars.push(hotbar as Hotbar);
}
/**
* Finally, make sure that the catalog entity hotbar item is in place.
* Just in case something else removed it.
*
* if every hotbar has elements that all not the `catalog-entity` item
*/
if (hotbars.every(hotbar => hotbar.items.every(item => item?.entity?.uid !== "catalog-entity"))) {
// note, we will add a new whole hotbar here called "default" if that was previously removed
const di = getLegacyGlobalDiForExtensionApi();
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
const defaultHotbar = hotbars.find(hotbar => hotbar.name === "default");
const { metadata: { uid, name, source }} = catalogCatalogEntity;
if (defaultHotbar) {
const freeIndex = defaultHotbar.items.findIndex(i => i === null);
if (freeIndex === -1) {
// making a new hotbar is less destructive if the first hotbar
// called "default" is full than overriding a hotbar item
const hotbar = getEmptyHotbar("initial");
hotbar.items[0] = { entity: { uid, name, source }};
hotbars.unshift(hotbar);
} else {
defaultHotbar.items[freeIndex] = { entity: { uid, name, source }};
}
} else {
const hotbar = getEmptyHotbar("default");
hotbar.items[0] = { entity: { uid, name, source }};
hotbars.unshift(hotbar);
}
}
} catch (error) {
// ignore files being missing
if (isErrnoException(error) && error.code !== "ENOENT") {
throw error;
}
}
store.set("hotbars", hotbars);
},
};
},
injectionToken: hotbarStoreMigrationInjectionToken,
});
export default v500Beta10HotbarStoreMigrationInjectable;
@@ -1,54 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Hotbar } from "../../../common/hotbars/types";
import catalogEntityRegistryInjectable from "../../catalog/entity-registry.injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token";
const v500Beta5HotbarStoreMigrationInjectable = getInjectable({
id: "v500-beta5-hotbar-store-migration",
instantiate: (di) => {
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
return {
version: "5.0.0-beta.5",
run(store) {
const rawHotbars = store.get("hotbars");
const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars : [];
for (const hotbar of hotbars) {
for (let i = 0; i < hotbar.items.length; i += 1) {
const item = hotbar.items[i];
if (!item) {
continue;
}
const entity = catalogEntityRegistry.findById(item.entity.uid);
if (!entity) {
// Clear disabled item
hotbar.items[i] = null;
} else {
// Save additional data
item.entity = {
...item.entity,
name: entity.metadata.name,
source: entity.metadata.source,
};
}
}
}
store.set("hotbars", hotbars);
},
};
},
injectionToken: hotbarStoreMigrationInjectionToken,
});
export default v500Beta5HotbarStoreMigrationInjectable;
@@ -3,8 +3,8 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable";
import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable";
import { kubectlApplyAllChannel } from "../../common/kube-helpers/channels";
import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable";
import resourceApplierInjectable from "../resource-applier/create-resource-applier.injectable";
import { getRequestChannelListenerInjectable } from "@k8slens/messaging";
@@ -15,14 +15,16 @@ const kubectlApplyAllChannelHandlerInjectable = getRequestChannelListenerInjecta
const getClusterById = di.inject(getClusterByIdInjectable);
const emitAppEvent = di.inject(emitAppEventInjectable);
return async ({
clusterId,
extraArgs,
resources,
}) => {
emitAppEvent({ name: "cluster", action: "kubectl-apply-all" });
return async (event) => {
const {
clusterId,
extraArgs,
resources,
} = event;
const cluster = getClusterById(clusterId);
emitAppEvent({ name: "cluster", action: "kubectl-apply-all" });
if (!cluster) {
return {
callWasSuccessful: false,
@@ -6,7 +6,6 @@ import { getInjectable } from "@ogre-tools/injectable";
import type { KubectlDependencies } from "./kubectl";
import { Kubectl } from "./kubectl";
import directoryForKubectlBinariesInjectable from "../../common/app-paths/directory-for-kubectl-binaries/directory-for-kubectl-binaries.injectable";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import kubectlDownloadingNormalizedArchInjectable from "./normalized-arch.injectable";
import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable";
import kubectlBinaryNameInjectable from "./binary-name.injectable";
@@ -20,6 +19,7 @@ import getBasenameOfPathInjectable from "../../common/path/get-basename.injectab
import loggerInjectable from "../../common/logger.injectable";
import execFileInjectable from "../../common/fs/exec-file.injectable";
import unlinkInjectable from "../../common/fs/unlink.injectable";
import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable";
export type CreateKubectl = (version: string) => Kubectl;
@@ -28,7 +28,7 @@ const createKubectlInjectable = getInjectable({
instantiate: (di): CreateKubectl => {
const dependencies: KubectlDependencies = {
userStore: di.inject(userStoreInjectable),
state: di.inject(userPreferencesStateInjectable),
directoryForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable),
normalizedDownloadArch: di.inject(kubectlDownloadingNormalizedArchInjectable),
normalizedDownloadPlatform: di.inject(normalizedPlatformInjectable),
@@ -3,8 +3,8 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable";
import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable";
import { kubectlDeleteAllChannel } from "../../common/kube-helpers/channels";
import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable";
import resourceApplierInjectable from "../resource-applier/create-resource-applier.injectable";
import { getRequestChannelListenerInjectable } from "@k8slens/messaging";
@@ -15,15 +15,16 @@ const kubectlDeleteAllChannelHandlerInjectable = getRequestChannelListenerInject
const emitAppEvent = di.inject(emitAppEventInjectable);
const getClusterById = di.inject(getClusterByIdInjectable);
return async ({
clusterId,
extraArgs,
resources,
}) => {
emitAppEvent({ name: "cluster", action: "kubectl-delete-all" });
return async (event) => {
const {
clusterId,
extraArgs,
resources,
} = event;
const cluster = getClusterById(clusterId);
emitAppEvent({ name: "cluster", action: "kubectl-delete-all" });
if (!cluster) {
return {
callWasSuccessful: false,
+9 -9
View File
@@ -7,7 +7,6 @@ import fs from "fs";
import { ensureDir, pathExists } from "fs-extra";
import * as lockFile from "proper-lockfile";
import { SemVer, coerce } from "semver";
import { defaultPackageMirror, packageMirrors } from "../../common/user-store/preferences-helpers";
import got from "got/dist/source";
import { promisify } from "util";
import stream from "stream";
@@ -20,6 +19,7 @@ import type { Logger } from "../../common/logger";
import type { ExecFile } from "../../common/fs/exec-file.injectable";
import { hasTypedProperty, isObject, isString, json } from "@k8slens/utilities";
import type { Unlink } from "../../common/fs/unlink.injectable";
import { packageMirrors, defaultPackageMirror } from "../../features/user-preferences/common/preferences-helpers";
const initScriptVersionString = "# lens-initscript v3";
@@ -30,7 +30,7 @@ export interface KubectlDependencies {
readonly kubectlBinaryName: string;
readonly bundledKubectlBinaryPath: string;
readonly baseBundeledBinariesDirectory: string;
readonly userStore: {
readonly state: {
readonly kubectlBinariesPath?: string;
readonly downloadBinariesPath?: string;
readonly downloadKubectlBinaries: boolean;
@@ -91,12 +91,12 @@ export class Kubectl {
}
public getPathFromPreferences() {
return this.dependencies.userStore.kubectlBinariesPath || this.getBundledPath();
return this.dependencies.state.kubectlBinariesPath || this.getBundledPath();
}
protected getDownloadDir() {
if (this.dependencies.userStore.downloadBinariesPath) {
return this.dependencies.joinPaths(this.dependencies.userStore.downloadBinariesPath, "kubectl");
if (this.dependencies.state.downloadBinariesPath) {
return this.dependencies.joinPaths(this.dependencies.state.downloadBinariesPath, "kubectl");
}
return this.dependencies.directoryForKubectlBinaries;
@@ -107,7 +107,7 @@ export class Kubectl {
return this.getBundledPath();
}
if (this.dependencies.userStore.downloadKubectlBinaries === false) {
if (this.dependencies.state.downloadKubectlBinaries === false) {
return this.getPathFromPreferences();
}
@@ -231,7 +231,7 @@ export class Kubectl {
}
public async ensureKubectl(): Promise<boolean> {
if (this.dependencies.userStore.downloadKubectlBinaries === false) {
if (this.dependencies.state.downloadKubectlBinaries === false) {
return true;
}
@@ -303,7 +303,7 @@ export class Kubectl {
protected async writeInitScripts() {
const binariesDir = this.dependencies.baseBundeledBinariesDirectory;
const kubectlPath = this.dependencies.userStore.downloadKubectlBinaries
const kubectlPath = this.dependencies.state.downloadKubectlBinaries
? this.dirname
: this.dependencies.getDirnameOfPath(this.getPathFromPreferences());
@@ -370,7 +370,7 @@ export class Kubectl {
protected getDownloadMirror(): string {
// MacOS packages are only available from default
const { url } = packageMirrors.get(this.dependencies.userStore.downloadMirror)
const { url } = packageMirrors.get(this.dependencies.state.downloadMirror)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
?? packageMirrors.get(defaultPackageMirror)!;
@@ -3,9 +3,9 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable";
import { getClusterIdFromHost } from "../../common/utils";
import { apiKubePrefix } from "../../common/vars";
import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable";
import type { GetClusterForRequest } from "./lens-proxy";
const getClusterForRequestInjectable = getInjectable({
@@ -6,12 +6,10 @@
import * as uuid from "uuid";
import { ProtocolHandlerExtension, ProtocolHandlerInternal, ProtocolHandlerInvalid } from "../../../common/protocol-handler";
import { delay, noop } from "@k8slens/utilities";
import type { ExtensionsStore, IsEnabledExtensionDescriptor } from "../../../extensions/extensions-store/extensions-store";
import { noop } from "@k8slens/utilities";
import type { LensProtocolRouterMain } from "../lens-protocol-router-main/lens-protocol-router-main";
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
import lensProtocolRouterMainInjectable from "../lens-protocol-router-main/lens-protocol-router-main.injectable";
import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable";
import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import { LensExtension } from "../../../extensions/lens-extension";
import type { ObservableMap } from "mobx";
@@ -23,6 +21,8 @@ import pathExistsInjectable from "../../../common/fs/path-exists.injectable";
import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable";
import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable";
import type { LensExtensionId } from "@k8slens/legacy-extensions";
import type { LensExtensionState } from "../../../features/extensions/enabled/common/state.injectable";
import enabledExtensionsStateInjectable from "../../../features/extensions/enabled/common/state.injectable";
function throwIfDefined(val: any): void {
if (val != null) {
@@ -33,7 +33,7 @@ function throwIfDefined(val: any): void {
describe("protocol router tests", () => {
let extensionInstances: ObservableMap<LensExtensionId, LensExtension>;
let lpr: LensProtocolRouterMain;
let enabledExtensions: Set<string>;
let enabledExtensions: ObservableMap<LensExtensionId, LensExtensionState>;
let broadcastMessageMock: jest.Mock;
beforeEach(async () => {
@@ -44,11 +44,7 @@ describe("protocol router tests", () => {
di.override(readJsonSyncInjectable, () => () => { throw new Error("tried call readJsonSync without override"); });
di.override(writeJsonSyncInjectable, () => () => { throw new Error("tried call writeJsonSync without override"); });
enabledExtensions = new Set();
di.override(extensionsStoreInjectable, () => ({
isEnabled: ({ id, isBundled }: IsEnabledExtensionDescriptor) => isBundled || enabledExtensions.has(id),
} as unknown as ExtensionsStore));
enabledExtensions = di.inject(enabledExtensionsStateInjectable);
di.permitSideEffects(getConfigurationFileModelInjectable);
@@ -95,7 +91,7 @@ describe("protocol router tests", () => {
});
extensionInstances.set(extId, ext);
enabledExtensions.add(extId);
enabledExtensions.set(extId, { name: "@mirantis/minikube", enabled: true });
lpr.addInternalHandler("/", noop);
@@ -105,14 +101,14 @@ describe("protocol router tests", () => {
expect(throwIfDefined(error)).not.toThrow();
}
expect(broadcastMessageMock).toHaveBeenCalledWith(ProtocolHandlerInternal, "lens://app", "matched");
try {
expect(await lpr.route("lens://extension/@mirantis/minikube")).toBeUndefined();
} catch (error) {
expect(throwIfDefined(error)).not.toThrow();
}
await delay(50);
expect(broadcastMessageMock).toHaveBeenCalledWith(ProtocolHandlerInternal, "lens://app", "matched");
expect(broadcastMessageMock).toHaveBeenCalledWith(ProtocolHandlerExtension, "lens://extension/@mirantis/minikube", "matched");
});
@@ -175,7 +171,7 @@ describe("protocol router tests", () => {
});
extensionInstances.set(extId, ext);
enabledExtensions.add(extId);
enabledExtensions.set(extId, { name: "@foobar/icecream", enabled: true });
try {
expect(await lpr.route("lens://extension/@foobar/icecream/page/foob")).toBeUndefined();
@@ -183,7 +179,6 @@ describe("protocol router tests", () => {
expect(throwIfDefined(error)).not.toThrow();
}
await delay(50);
expect(called).toBe("foob");
expect(broadcastMessageMock).toBeCalledWith(ProtocolHandlerExtension, "lens://extension/@foobar/icecream/page/foob", "matched");
});
@@ -214,7 +209,7 @@ describe("protocol router tests", () => {
});
extensionInstances.set(extId, ext);
enabledExtensions.add(extId);
enabledExtensions.set(extId, { name: "@foobar/icecream", enabled: true });
}
{
@@ -240,19 +235,15 @@ describe("protocol router tests", () => {
});
extensionInstances.set(extId, ext);
enabledExtensions.add(extId);
enabledExtensions.set(extId, { name: "icecream", enabled: true });
}
enabledExtensions.add("@foobar/icecream");
enabledExtensions.add("icecream");
try {
expect(await lpr.route("lens://extension/icecream/page")).toBeUndefined();
} catch (error) {
expect(throwIfDefined(error)).not.toThrow();
}
await delay(50);
expect(called).toBe(1);
expect(broadcastMessageMock).toBeCalledWith(ProtocolHandlerExtension, "lens://extension/icecream/page", "matched");
@@ -5,22 +5,21 @@
import { getInjectable } from "@ogre-tools/injectable";
import extensionLoaderInjectable from "../../../extensions/extension-loader/extension-loader.injectable";
import { LensProtocolRouterMain } from "./lens-protocol-router-main";
import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable";
import showApplicationWindowInjectable from "../../start-main-application/lens-window/show-application-window.injectable";
import broadcastMessageInjectable from "../../../common/ipc/broadcast-message.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import isExtensionEnabledInjectable from "../../../features/extensions/enabled/common/is-enabled.injectable";
const lensProtocolRouterMainInjectable = getInjectable({
id: "lens-protocol-router-main",
instantiate: (di) =>
new LensProtocolRouterMain({
extensionLoader: di.inject(extensionLoaderInjectable),
extensionsStore: di.inject(extensionsStoreInjectable),
showApplicationWindow: di.inject(showApplicationWindowInjectable),
broadcastMessage: di.inject(broadcastMessageInjectable),
logger: di.inject(loggerInjectable),
}),
instantiate: (di) => new LensProtocolRouterMain({
extensionLoader: di.inject(extensionLoaderInjectable),
isExtensionEnabled: di.inject(isExtensionEnabledInjectable),
showApplicationWindow: di.inject(showApplicationWindowInjectable),
broadcastMessage: di.inject(broadcastMessageInjectable),
logger: di.inject(loggerInjectable),
}),
});
export default lensProtocolRouterMainInjectable;
@@ -119,7 +119,13 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter {
const rawUrl = url.toString(); // for sending to renderer
const attempt = super._routeToInternal(url);
this.disposers.push(when(() => this.rendererLoaded, () => this.dependencies.broadcastMessage(proto.ProtocolHandlerInternal, rawUrl, attempt)));
const sendRoutingToRenderer = () => this.dependencies.broadcastMessage(proto.ProtocolHandlerInternal, rawUrl, attempt);
if (this.rendererLoaded) {
sendRoutingToRenderer();
} else {
this.disposers.push(when(() => this.rendererLoaded, sendRoutingToRenderer));
}
return attempt;
}
@@ -136,7 +142,13 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter {
*/
const attempt = await super._routeToExtension(new URLParse(url.toString(), true));
this.disposers.push(when(() => this.rendererLoaded, () => this.dependencies.broadcastMessage(proto.ProtocolHandlerExtension, rawUrl, attempt)));
const sendRoutingToRenderer = () => this.dependencies.broadcastMessage(proto.ProtocolHandlerExtension, rawUrl, attempt);
if (this.rendererLoaded) {
sendRoutingToRenderer();
} else {
this.disposers.push(when(() => this.rendererLoaded, sendRoutingToRenderer));
}
return attempt;
}
@@ -3,17 +3,17 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { UserStore } from "../../../common/user-store";
import type { ShellSessionArgs, ShellSessionDependencies } from "../shell-session";
import { ShellSession } from "../shell-session";
import type { ModifyTerminalShellEnv } from "../shell-env-modifier/modify-terminal-shell-env.injectable";
import type { JoinPaths } from "../../../common/path/join-paths.injectable";
import type { GetDirnameOfPath } from "../../../common/path/get-dirname.injectable";
import type { GetBasenameOfPath } from "../../../common/path/get-basename.injectable";
import type { UserPreferencesState } from "../../../features/user-preferences/common/state.injectable";
export interface LocalShellSessionDependencies extends ShellSessionDependencies {
readonly directoryForBinaries: string;
readonly userStore: UserStore;
readonly state: UserPreferencesState;
modifyTerminalShellEnv: ModifyTerminalShellEnv;
joinPaths: JoinPaths;
getDirnameOfPath: GetDirnameOfPath;
@@ -50,8 +50,8 @@ export class LocalShellSession extends ShellSession {
}
protected async getShellArgs(shell: string): Promise<string[]> {
const pathFromPreferences = this.dependencies.userStore.kubectlBinariesPath || this.kubectl.getBundledPath();
const kubectlPathDir = this.dependencies.userStore.downloadKubectlBinaries
const pathFromPreferences = this.dependencies.state.kubectlBinariesPath || this.kubectl.getBundledPath();
const kubectlPathDir = this.dependencies.state.downloadKubectlBinaries
? this.dependencies.directoryContainingKubectl
: this.dependencies.getDirnameOfPath(pathFromPreferences);
@@ -12,19 +12,19 @@ import isMacInjectable from "../../../common/vars/is-mac.injectable";
import type { Cluster } from "../../../common/cluster/cluster";
import isWindowsInjectable from "../../../common/vars/is-windows.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import userStoreInjectable from "../../../common/user-store/user-store.injectable";
import type WebSocket from "ws";
import getDirnameOfPathInjectable from "../../../common/path/get-dirname.injectable";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable";
import computeShellEnvironmentInjectable from "../../../features/shell-sync/main/compute-shell-environment.injectable";
import spawnPtyInjectable from "../spawn-pty.injectable";
import userShellSettingInjectable from "../../../common/user-store/shell-setting.injectable";
import appNameInjectable from "../../../common/vars/app-name.injectable";
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
import statInjectable from "../../../common/fs/stat.injectable";
import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable";
import userPreferencesStateInjectable from "../../../features/user-preferences/common/state.injectable";
import userShellSettingInjectable from "../../../features/user-preferences/common/shell-setting.injectable";
export interface OpenLocalShellSessionArgs {
websocket: WebSocket;
@@ -44,7 +44,7 @@ const openLocalShellSessionInjectable = getInjectable({
isMac: di.inject(isMacInjectable),
isWindows: di.inject(isWindowsInjectable),
logger: di.inject(loggerInjectable),
userStore: di.inject(userStoreInjectable),
state: di.inject(userPreferencesStateInjectable),
userShellSetting: di.inject(userShellSettingInjectable),
appName: di.inject(appNameInjectable),
buildVersion: di.inject(buildVersionInjectable),
@@ -14,7 +14,6 @@ import loggerInjectable from "../../../common/logger.injectable";
import createKubeJsonApiForClusterInjectable from "../../../common/k8s-api/create-kube-json-api-for-cluster.injectable";
import computeShellEnvironmentInjectable from "../../../features/shell-sync/main/compute-shell-environment.injectable";
import spawnPtyInjectable from "../spawn-pty.injectable";
import userShellSettingInjectable from "../../../common/user-store/shell-setting.injectable";
import appNameInjectable from "../../../common/vars/app-name.injectable";
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
@@ -22,6 +21,7 @@ import statInjectable from "../../../common/fs/stat.injectable";
import createKubeApiInjectable from "../../../common/k8s-api/create-kube-api.injectable";
import loadProxyKubeconfigInjectable from "../../cluster/load-proxy-kubeconfig.injectable";
import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable";
import userShellSettingInjectable from "../../../features/user-preferences/common/shell-setting.injectable";
export interface NodeShellSessionArgs {
websocket: WebSocket;
@@ -1,23 +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 { onLoadOfApplicationInjectionToken } from "@k8slens/application";
import syncWeblinksInjectable from "../../catalog-sources/sync-weblinks.injectable";
const setupSyncingOfWeblinksInjectable = getInjectable({
id: "setup-syncing-of-weblinks",
instantiate: (di) => ({
run: () => {
const syncWeblinks = di.inject(syncWeblinksInjectable);
syncWeblinks();
},
}),
injectionToken: onLoadOfApplicationInjectionToken,
});
export default setupSyncingOfWeblinksInjectable;
@@ -1,26 +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 userStoreFileNameMigrationInjectable from "../../common/user-store/file-name-migration.injectable";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application";
import initDefaultUpdateChannelInjectable from "../vars/default-update-channel/init.injectable";
const initUserStoreInjectable = getInjectable({
id: "init-user-store",
instantiate: (di) => ({
run: async () => {
const userStore = di.inject(userStoreInjectable);
const userStoreFileNameMigration = di.inject(userStoreFileNameMigrationInjectable);
await userStoreFileNameMigration();
userStore.load();
},
runAfter: initDefaultUpdateChannelInjectable,
}),
injectionToken: beforeApplicationIsLoadingInjectionToken,
});
export default initUserStoreInjectable;
@@ -1,36 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// Switch representation of hiddenTableColumns in store
import { getInjectable } from "@ogre-tools/injectable";
import { userStoreMigrationInjectionToken } from "../../../common/user-store/migrations-token";
interface PreV500Alpha3UserPreferencesModel {
hiddenTableColumns?: Record<string, string[]>;
}
const v500Alpha3UserStoreMigrationInjectable = getInjectable({
id: "v5.0.0-alpha.3-user-store-migration",
instantiate: () => ({
version: "5.0.0-alpha.3",
run(store) {
const preferences = (store.get("preferences") ?? {}) as PreV500Alpha3UserPreferencesModel;
const oldHiddenTableColumns = preferences.hiddenTableColumns;
if (!oldHiddenTableColumns) {
return;
}
store.set("preferences", {
...preferences,
hiddenTableColumns: Object.entries(oldHiddenTableColumns),
});
},
}),
injectionToken: userStoreMigrationInjectionToken,
});
export default v500Alpha3UserStoreMigrationInjectable;
@@ -1,91 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { ClusterStoreModel } from "../../../common/cluster-store/cluster-store";
import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../../common/user-store";
import { isErrnoException } from "@k8slens/utilities";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import isLogicalChildPathInjectable from "../../../common/path/is-logical-child-path.injectable";
import getDirnameOfPathInjectable from "../../../common/path/get-dirname.injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { userStoreMigrationInjectionToken } from "../../../common/user-store/migrations-token";
import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable";
import homeDirectoryPathInjectable from "../../../common/os/home-directory-path.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import pathExistsSyncInjectable from "../../../common/fs/path-exists-sync.injectable";
const v503Beta1UserStoreMigrationInjectable = getInjectable({
id: "v5.0.3-beta.1-user-store-migration",
instantiate: (di) => {
const userDataPath = di.inject(directoryForUserDataInjectable);
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
const joinPaths = di.inject(joinPathsInjectable);
const logger = di.inject(loggerInjectable);
const isLogicalChildPath = di.inject(isLogicalChildPathInjectable);
const getDirnameOfPath = di.inject(getDirnameOfPathInjectable);
const readJsonSync = di.inject(readJsonSyncInjectable);
const homeDirectoryPath = di.inject(homeDirectoryPathInjectable);
const pathExistsSync = di.inject(pathExistsSyncInjectable);
return {
version: "5.0.3-beta.1",
run(store) {
try {
const { syncKubeconfigEntries = [], ...preferences } = (store.get("preferences") ?? {}) as UserPreferencesModel;
const { clusters = [] }: ClusterStoreModel = readJsonSync(joinPaths(userDataPath, "lens-cluster-store.json"), "utf-8") ?? {};
const extensionDataDir = joinPaths(userDataPath, "extension_data");
const syncPaths = new Set(syncKubeconfigEntries.map(s => s.filePath));
syncPaths.add(joinPaths(homeDirectoryPath, ".kube"));
for (const cluster of clusters) {
if (!cluster.kubeConfigPath) {
continue;
}
const dirOfKubeconfig = getDirnameOfPath(cluster.kubeConfigPath);
if (dirOfKubeconfig === kubeConfigsPath) {
logger.info(`Skipping ${cluster.id} because kubeConfigPath is under the stored KubeConfig folder`);
continue;
}
if (syncPaths.has(cluster.kubeConfigPath) || syncPaths.has(dirOfKubeconfig)) {
logger.info(`Skipping ${cluster.id} because kubeConfigPath is already being synced`);
continue;
}
if (isLogicalChildPath(extensionDataDir, cluster.kubeConfigPath)) {
logger.info(`Skipping ${cluster.id} because kubeConfigPath is placed under an extension_data folder`);
continue;
}
if (!pathExistsSync(cluster.kubeConfigPath)) {
logger.info(`Skipping ${cluster.id} because kubeConfigPath no longer exists`);
continue;
}
logger.info(`Adding ${cluster.kubeConfigPath} from ${cluster.id} to sync paths`);
syncPaths.add(cluster.kubeConfigPath);
}
const updatedSyncEntries: KubeconfigSyncEntry[] = [...syncPaths].map(filePath => ({ filePath }));
logger.info("Final list of synced paths", updatedSyncEntries);
store.set("preferences", { ...preferences, syncKubeconfigEntries: updatedSyncEntries });
} catch (error) {
if (isErrnoException(error) && error.code !== "ENOENT") {
// ignore files being missing
throw error;
}
}
},
};
},
injectionToken: userStoreMigrationInjectionToken,
});
export default v503Beta1UserStoreMigrationInjectable;
@@ -1,32 +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 { reaction } from "mobx";
import userStoreInjectable from "../../common/user-store/user-store.injectable";
import setLoginItemSettingsInjectable from "../electron-app/features/set-login-item-settings.injectable";
import { onLoadOfApplicationInjectionToken } from "@k8slens/application";
const setupSyncOpenAtLoginWithOsInjectable = getInjectable({
id: "setup-sync-open-at-login-with-os",
instantiate: (di) => ({
run: () => {
const setLoginItemSettings = di.inject(setLoginItemSettingsInjectable);
const userStore = di.inject(userStoreInjectable);
reaction(() => userStore.openAtLogin, openAtLogin => {
setLoginItemSettings({
openAtLogin,
openAsHidden: true,
args: ["--hidden"],
});
}, {
fireImmediately: true,
});
},
}),
injectionToken: onLoadOfApplicationInjectionToken,
});
export default setupSyncOpenAtLoginWithOsInjectable;
@@ -1,24 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export const lensWebsiteWeblinkId = "lens-website-link";
export const lensWebsiteLinkName = "Lens Website";
export const lensDocumentationWeblinkId = "lens-documentation-link";
export const lensDocumentationWeblinkName = "Lens Documentation";
export const lensForumsWeblinkId = "lens-forums-link";
export const lensForumsWeblinkName = "Lens Forums";
export const lensTwitterWeblinkId = "lens-twitter-link";
export const lensTwitterWeblinkName = "Lens on Twitter";
export const lensBlogWeblinkId = "lens-blog-link";
export const lensBlogWeblinkName = "Lens Official Blog";
export const kubernetesDocumentationWeblinkId = "kubernetes-documentation-link";
export const kubernetesDocumentationWeblinkName = "Kubernetes Documentation";
@@ -1,35 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { docsUrl, forumsUrl } from "../../../common/vars";
import type { WeblinkData } from "../../../common/weblinks-store/weblink-store";
import { getInjectable } from "@ogre-tools/injectable";
import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token";
import * as links from "../links";
const v514WeblinkStoreMigrationInjectable = getInjectable({
id: "v5.1.4-weblink-store-migration",
instantiate: () => ({
version: "5.1.4",
run(store) {
const weblinksRaw = store.get("weblinks");
const weblinks = (Array.isArray(weblinksRaw) ? weblinksRaw : []) as WeblinkData[];
weblinks.push(
{ id: "https://k8slens.dev", name: links.lensWebsiteLinkName, url: "https://k8slens.dev" },
{ id: docsUrl, name: links.lensDocumentationWeblinkName, url: docsUrl },
{ id: forumsUrl, name: links.lensForumsWeblinkName, url: forumsUrl },
{ id: "https://twitter.com/k8slens", name: links.lensTwitterWeblinkName, url: "https://twitter.com/k8slens" },
{ id: "https://medium.com/k8slens", name: links.lensBlogWeblinkName, url: "https://medium.com/k8slens" },
{ id: "https://kubernetes.io/docs/home/", name: links.kubernetesDocumentationWeblinkName, url: "https://kubernetes.io/docs/home/" },
);
store.set("weblinks", weblinks);
},
}),
injectionToken: weblinkStoreMigrationInjectionToken,
});
export default v514WeblinkStoreMigrationInjectable;
@@ -1,61 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { WeblinkData } from "../../../common/weblinks-store/weblink-store";
import * as links from "../links";
import { getInjectable } from "@ogre-tools/injectable";
import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token";
const v545Beta1WeblinkStoreMigrationInjectable = getInjectable({
id: "v5.4.5-beta.1-weblink-store-migration",
instantiate: () => ({
version: "5.4.5-beta.1 || >=5.5.0-alpha.0",
run(store) {
const weblinksRaw = store.get("weblinks");
const weblinks = (Array.isArray(weblinksRaw) ? weblinksRaw : []) as WeblinkData[];
const lensWebsite = weblinks.find(weblink => weblink.name === links.lensWebsiteLinkName);
if (lensWebsite) {
lensWebsite.id = links.lensWebsiteWeblinkId;
}
const lensDocumentationWeblink = weblinks.find(weblink => weblink.name === links.lensDocumentationWeblinkName);
if (lensDocumentationWeblink) {
lensDocumentationWeblink.id = links.lensDocumentationWeblinkId;
}
const lensForumsWeblink = weblinks.find(weblink => weblink.name === links.lensForumsWeblinkName);
if (lensForumsWeblink) {
lensForumsWeblink.id = links.lensForumsWeblinkId;
}
const lensTwitterWeblink = weblinks.find(weblink => weblink.name === links.lensTwitterWeblinkName);
if (lensTwitterWeblink) {
lensTwitterWeblink.id = links.lensTwitterWeblinkId;
}
const lensBlogWeblink = weblinks.find(weblink => weblink.name === links.lensBlogWeblinkName);
if (lensBlogWeblink) {
lensBlogWeblink.id = links.lensBlogWeblinkId;
}
const kubernetesDocumentationWeblink = weblinks.find(weblink => weblink.name === links.kubernetesDocumentationWeblinkName);
if (kubernetesDocumentationWeblink) {
kubernetesDocumentationWeblink.id = links.kubernetesDocumentationWeblinkId;
}
store.set("weblinks", weblinks);
},
}),
injectionToken: weblinkStoreMigrationInjectionToken,
});
export default v545Beta1WeblinkStoreMigrationInjectable;
@@ -1,44 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { docsUrl, forumsUrl } from "../../../common/vars";
import type { WeblinkData } from "../../../common/weblinks-store/weblink-store";
import { getInjectable } from "@ogre-tools/injectable";
import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token";
import { lensDocumentationWeblinkId, lensForumsWeblinkId } from "../links";
import { applicationInformationToken } from "@k8slens/application";
const currentVersionWeblinkStoreMigrationInjectable = getInjectable({
id: "current-version-weblink-store-migration",
instantiate: (di) => {
const { version } = di.inject(applicationInformationToken);
return {
version, // Run always after upgrade
run(store) {
const weblinksRaw = store.get("weblinks");
const weblinks = (Array.isArray(weblinksRaw) ? weblinksRaw : []) as WeblinkData[];
const forumsWeblink = weblinks.find(weblink => weblink.id === lensForumsWeblinkId);
if (forumsWeblink) {
forumsWeblink.url = forumsUrl;
}
const docsWeblink = weblinks.find(weblink => weblink.id === lensDocumentationWeblinkId);
if (docsWeblink) {
docsWeblink.url = docsUrl;
}
const removedSlackLink = weblinks.filter(weblink => weblink.id !== "lens-slack-link");
store.set("weblinks", removedSlackLink);
},
};
},
injectionToken: weblinkStoreMigrationInjectionToken,
});
export default currentVersionWeblinkStoreMigrationInjectable;