mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove isTestEnv
- Make all migration declarations injectable using a token - Make all migrations injectable using a token for the renderer side (instead of clearing them based on the truthiness of ipcRenderer) Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
afee784737
commit
f0f06f53d2
@ -14,7 +14,6 @@ import { Singleton, toJS } from "./utils";
|
||||
import logger from "../main/logger";
|
||||
import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc";
|
||||
import isEqual from "lodash/isEqual";
|
||||
import { isTestEnv } from "./vars";
|
||||
import { kebabCase } from "lodash";
|
||||
import { getLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import directoryForUserDataInjectable from "./app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
@ -40,22 +39,15 @@ export abstract class BaseStore<T> extends Singleton {
|
||||
protected constructor(protected params: BaseStoreParams<T>) {
|
||||
super();
|
||||
makeObservable(this);
|
||||
|
||||
if (ipcRenderer) {
|
||||
params.migrations = undefined; // don't run migrations on renderer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be called after the last child's constructor is finished (or just before it finishes)
|
||||
*/
|
||||
load() {
|
||||
if (!isTestEnv) {
|
||||
logger.info(`[${kebabCase(this.displayName).toUpperCase()}]: LOADING from ${this.path} ...`);
|
||||
}
|
||||
logger.debug(`[${kebabCase(this.displayName).toUpperCase()}]: LOADING from ${this.path} ...`);
|
||||
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const getConfigurationFileModel = di.inject(getConfigurationFileModelInjectable);
|
||||
|
||||
this.storeConfig = getConfigurationFileModel({
|
||||
@ -72,10 +64,7 @@ export abstract class BaseStore<T> extends Singleton {
|
||||
}
|
||||
|
||||
this.enableSync();
|
||||
|
||||
if (!isTestEnv) {
|
||||
logger.info(`[${kebabCase(this.displayName).toUpperCase()}]: LOADED from ${this.path}`);
|
||||
}
|
||||
logger.debug(`[${kebabCase(this.displayName).toUpperCase()}]: LOADED from ${this.path}`);
|
||||
}
|
||||
|
||||
get name() {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
import type { CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
|
||||
import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity";
|
||||
import { productName } from "../vars";
|
||||
import { WeblinkStore } from "../weblink-store";
|
||||
import { WeblinkStore } from "../weblinks/store";
|
||||
|
||||
export type WebLinkStatusPhase = "available" | "unavailable";
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ClusterStore } from "./cluster-store";
|
||||
import { createClusterInjectionToken } from "../cluster/create-cluster-injection-token";
|
||||
import readClusterConfigSyncInjectable from "./read-cluster-config.injectable";
|
||||
import { clusterStoreMigrationsInjectionToken } from "./migrations";
|
||||
|
||||
const clusterStoreInjectable = getInjectable({
|
||||
id: "cluster-store",
|
||||
@ -16,6 +17,7 @@ const clusterStoreInjectable = getInjectable({
|
||||
return ClusterStore.createInstance({
|
||||
createCluster: di.inject(createClusterInjectionToken),
|
||||
readClusterConfigSync: di.inject(readClusterConfigSyncInjectable),
|
||||
migrations: di.inject(clusterStoreMigrationsInjectionToken),
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@ import { ipcMain, ipcRenderer, webFrame } from "electron";
|
||||
import { action, comparer, computed, makeObservable, observable, reaction } from "mobx";
|
||||
import { BaseStore } from "../base-store";
|
||||
import { Cluster } from "../cluster/cluster";
|
||||
import migrations from "../../migrations/cluster-store";
|
||||
import logger from "../../main/logger";
|
||||
import { appEventBus } from "../app-event-bus/event-bus";
|
||||
import { ipcMainHandle } from "../ipc";
|
||||
@ -18,6 +17,7 @@ import { requestInitialClusterStates } from "../../renderer/ipc";
|
||||
import { clusterStates } from "../ipc/cluster";
|
||||
import type { CreateCluster } from "../cluster/create-cluster-injection-token";
|
||||
import type { ReadClusterConfigSync } from "./read-cluster-config.injectable";
|
||||
import type { Migrations } from "conf/dist/source/types";
|
||||
|
||||
export interface ClusterStoreModel {
|
||||
clusters?: ClusterModel[];
|
||||
@ -26,6 +26,7 @@ export interface ClusterStoreModel {
|
||||
interface Dependencies {
|
||||
createCluster: CreateCluster;
|
||||
readClusterConfigSync: ReadClusterConfigSync;
|
||||
readonly migrations: Migrations<ClusterStoreModel> | undefined;
|
||||
}
|
||||
|
||||
export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
@ -34,14 +35,14 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
|
||||
protected disposer = disposer();
|
||||
|
||||
constructor(private dependencies: Dependencies) {
|
||||
constructor(protected readonly dependencies: Dependencies) {
|
||||
super({
|
||||
configName: "lens-cluster-store",
|
||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||
syncOptions: {
|
||||
equals: comparer.structural,
|
||||
},
|
||||
migrations,
|
||||
migrations: dependencies.migrations,
|
||||
});
|
||||
|
||||
makeObservable(this);
|
||||
|
||||
12
src/common/cluster-store/migrations.ts
Normal file
12
src/common/cluster-store/migrations.ts
Normal file
@ -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 { Migrations } from "conf/dist/source/types";
|
||||
import type { ClusterStoreModel } from "./cluster-store";
|
||||
|
||||
export const clusterStoreMigrationsInjectionToken = getInjectionToken<Migrations<ClusterStoreModel> | undefined>({
|
||||
id: "cluster-store-migrations-token",
|
||||
});
|
||||
@ -5,14 +5,31 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import fsInjectable from "./fs.injectable";
|
||||
|
||||
export type ReadFileSync = (filePath: string) => string;
|
||||
export interface ReadFileAsBufferOptions {
|
||||
asBuffer: true;
|
||||
}
|
||||
|
||||
export interface ReadFileAsStringOptions {
|
||||
asBuffer: false;
|
||||
}
|
||||
|
||||
export interface ReadFileSync {
|
||||
(filePath: string, options?: ReadFileAsStringOptions): string;
|
||||
(filePath: string, options: ReadFileAsBufferOptions): Buffer;
|
||||
}
|
||||
|
||||
const readFileSyncInjectable = getInjectable({
|
||||
id: "read-file-sync",
|
||||
instantiate: (di): ReadFileSync => {
|
||||
instantiate: (di) => {
|
||||
const { readFileSync } = di.inject(fsInjectable);
|
||||
|
||||
return (filePath) => readFileSync(filePath, "utf-8");
|
||||
return ((filePath, options = { asBuffer: false }) => {
|
||||
if (options.asBuffer) {
|
||||
return readFileSync(filePath);
|
||||
} else {
|
||||
return readFileSync(filePath, "utf-8");
|
||||
}
|
||||
}) as ReadFileSync;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
12
src/common/hotbars/migrations.ts
Normal file
12
src/common/hotbars/migrations.ts
Normal file
@ -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 { Migrations } from "conf/dist/source/types";
|
||||
import type { HotbarStoreModel } from "./store";
|
||||
|
||||
export const hotbarStoreMigrationsInjectionToken = getInjectionToken<Migrations<HotbarStoreModel> | undefined>({
|
||||
id: "hotbar-store-migrations-token",
|
||||
});
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
import { action, comparer, observable, makeObservable, computed } from "mobx";
|
||||
import { BaseStore } from "../base-store";
|
||||
import migrations from "../../migrations/hotbar-store";
|
||||
import { toJS } from "../utils";
|
||||
import type { CatalogEntity } from "../catalog";
|
||||
import { broadcastMessage } from "../ipc";
|
||||
@ -15,6 +14,7 @@ import { hotbarTooManyItemsChannel } from "../ipc/hotbar";
|
||||
import type { GeneralEntity } from "../catalog-entities";
|
||||
import type { Logger } from "../logger";
|
||||
import assert from "assert";
|
||||
import type { Migrations } from "conf/dist/source/types";
|
||||
|
||||
export interface HotbarStoreModel {
|
||||
hotbars: Hotbar[];
|
||||
@ -24,6 +24,7 @@ export interface HotbarStoreModel {
|
||||
interface Dependencies {
|
||||
readonly catalogCatalogEntity: GeneralEntity;
|
||||
readonly logger: Logger;
|
||||
readonly migrations: Migrations<HotbarStoreModel> | undefined;
|
||||
}
|
||||
|
||||
export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
@ -38,7 +39,7 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
syncOptions: {
|
||||
equals: comparer.structural,
|
||||
},
|
||||
migrations,
|
||||
migrations: dependencies.migrations,
|
||||
});
|
||||
|
||||
makeObservable(this);
|
||||
|
||||
@ -17,12 +17,6 @@ import type { PartialDeep } from "type-fest";
|
||||
|
||||
export const kubeConfigDefaultPath = path.join(os.homedir(), ".kube", "config");
|
||||
|
||||
export function loadConfigFromFileSync(filePath: string): ConfigResult {
|
||||
const content = fse.readFileSync(resolvePath(filePath), "utf-8");
|
||||
|
||||
return loadConfigFromString(content);
|
||||
}
|
||||
|
||||
export async function loadConfigFromFile(filePath: string): Promise<ConfigResult> {
|
||||
const content = await fse.readFile(resolvePath(filePath), "utf-8");
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import { app, ipcMain } from "electron";
|
||||
import winston, { format } from "winston";
|
||||
import type Transport from "winston-transport";
|
||||
import { consoleFormat } from "winston-console-format";
|
||||
import { isDebugging, isTestEnv } from "./vars";
|
||||
import { isDebugging, isProduction } from "./vars";
|
||||
import BrowserConsole from "winston-transport-browserconsole";
|
||||
|
||||
export interface Logger {
|
||||
@ -18,13 +18,8 @@ export interface Logger {
|
||||
silly: (message: string, ...args: any) => void;
|
||||
}
|
||||
|
||||
const logLevel = process.env.LOG_LEVEL
|
||||
? process.env.LOG_LEVEL
|
||||
: isDebugging
|
||||
? "debug"
|
||||
: isTestEnv
|
||||
? "error"
|
||||
: "info";
|
||||
const defaultLogLevel = isDebugging ? "debug" : "info";
|
||||
const logLevel = process.env.LOG_LEVEL || defaultLogLevel;
|
||||
|
||||
const transports: Transport[] = [];
|
||||
|
||||
@ -51,7 +46,8 @@ if (ipcMain) {
|
||||
}),
|
||||
);
|
||||
|
||||
if (!isTestEnv) {
|
||||
// TODO: replace logger with injectable
|
||||
if (isProduction) {
|
||||
transports.push(
|
||||
new winston.transports.File({
|
||||
handleExceptions: false,
|
||||
|
||||
16
src/common/user-store/migrations.ts
Normal file
16
src/common/user-store/migrations.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 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 { Migrations } from "conf/dist/source/types";
|
||||
import type { UserStoreModel } from "./user-store";
|
||||
|
||||
export const userStoreMigrationsInjectionToken = getInjectionToken<Migrations<UserStoreModel> | undefined>({
|
||||
id: "user-store-migrations-token",
|
||||
});
|
||||
|
||||
export const userStorePreMigrationsInjectionToken = getInjectionToken<() => void>({
|
||||
id: "user-store-pre-migrations-token",
|
||||
});
|
||||
@ -3,23 +3,25 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { ipcMain } from "electron";
|
||||
import userStoreFileNameMigrationInjectable from "./file-name-migration.injectable";
|
||||
import { UserStore } from "./user-store";
|
||||
import selectedUpdateChannelInjectable from "../application-update/selected-update-channel/selected-update-channel.injectable";
|
||||
import { userStoreMigrationsInjectionToken, userStorePreMigrationsInjectionToken } from "./migrations";
|
||||
|
||||
const userStoreInjectable = getInjectable({
|
||||
id: "user-store",
|
||||
|
||||
instantiate: (di) => {
|
||||
const preMigrations = di.injectMany(userStorePreMigrationsInjectionToken);
|
||||
|
||||
UserStore.resetInstance();
|
||||
|
||||
if (ipcMain) {
|
||||
di.inject(userStoreFileNameMigrationInjectable);
|
||||
for (const preMigration of preMigrations) {
|
||||
preMigration();
|
||||
}
|
||||
|
||||
return UserStore.createInstance({
|
||||
selectedUpdateChannel: di.inject(selectedUpdateChannelInjectable),
|
||||
migrations: di.inject(userStoreMigrationsInjectionToken),
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@ import { app } from "electron";
|
||||
import semver from "semver";
|
||||
import { action, computed, observable, reaction, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx";
|
||||
import { BaseStore } from "../base-store";
|
||||
import migrations from "../../migrations/user-store";
|
||||
import { getAppVersion } from "../utils/app-version";
|
||||
import { kubeConfigDefaultPath } from "../kube-helpers";
|
||||
import { appEventBus } from "../app-event-bus/event-bus";
|
||||
@ -17,6 +16,7 @@ import type { UserPreferencesModel, StoreType } from "./preferences-helpers";
|
||||
import logger from "../../main/logger";
|
||||
import type { SelectedUpdateChannel } from "../application-update/selected-update-channel/selected-update-channel.injectable";
|
||||
import type { UpdateChannelId } from "../application-update/update-channels";
|
||||
import type { Migrations } from "conf/dist/source/types";
|
||||
|
||||
export interface UserStoreModel {
|
||||
lastSeenAppVersion: string;
|
||||
@ -24,7 +24,8 @@ export interface UserStoreModel {
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
selectedUpdateChannel: SelectedUpdateChannel;
|
||||
readonly selectedUpdateChannel: SelectedUpdateChannel;
|
||||
readonly migrations: Migrations<UserStoreModel> | undefined;
|
||||
}
|
||||
|
||||
export class UserStore extends BaseStore<UserStoreModel> /* implements UserStoreFlatModel (when strict null is enabled) */ {
|
||||
@ -33,7 +34,7 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
||||
constructor(private readonly dependencies: Dependencies) {
|
||||
super({
|
||||
configName: "lens-user-store",
|
||||
migrations,
|
||||
migrations: dependencies.migrations,
|
||||
});
|
||||
|
||||
makeObservable(this);
|
||||
|
||||
@ -11,16 +11,13 @@ const environmentVariablesInjectable = getInjectable({
|
||||
// IMPORTANT: The syntax needs to be exactly this in order to make environment variable values
|
||||
// hard-coded at compile-time by Webpack.
|
||||
const NODE_ENV = process.env.NODE_ENV;
|
||||
const JEST_WORKER_ID = process.env.JEST_WORKER_ID;
|
||||
const CICD = process.env.CICD;
|
||||
|
||||
return {
|
||||
// Compile-time environment variables
|
||||
NODE_ENV,
|
||||
JEST_WORKER_ID,
|
||||
CICD,
|
||||
|
||||
// Runtime environment variables
|
||||
CICD: process.env.CICD,
|
||||
LENS_DISABLE_GPU: process.env.LENS_DISABLE_GPU,
|
||||
};
|
||||
},
|
||||
|
||||
@ -28,11 +28,6 @@ export const isLinux = process.platform === "linux";
|
||||
export const isDebugging = ["true", "1", "yes", "y", "on"].includes((process.env.DEBUG ?? "").toLowerCase());
|
||||
export const isSnap = !!process.env.SNAP;
|
||||
|
||||
/**
|
||||
* @deprecated Switch to using isTestEnvInjectable
|
||||
*/
|
||||
export const isTestEnv = !!process.env.JEST_WORKER_ID;
|
||||
|
||||
/**
|
||||
* @deprecated Switch to using isProductionInjectable
|
||||
*/
|
||||
@ -41,7 +36,7 @@ export const isProduction = process.env.NODE_ENV === "production";
|
||||
/**
|
||||
* @deprecated Switch to using isDevelopmentInjectable
|
||||
*/
|
||||
export const isDevelopment = !isTestEnv && !isProduction;
|
||||
export const isDevelopment = !isProduction;
|
||||
|
||||
export const productName = packageInfo.productName;
|
||||
|
||||
|
||||
@ -4,17 +4,11 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import isProductionInjectable from "./is-production.injectable";
|
||||
import isTestEnvInjectable from "./is-test-env.injectable";
|
||||
|
||||
const isDevelopmentInjectable = getInjectable({
|
||||
id: "is-development",
|
||||
|
||||
instantiate: (di) => {
|
||||
const isProduction = di.inject(isProductionInjectable);
|
||||
const isTestEnv = di.inject(isTestEnvInjectable);
|
||||
|
||||
return !isTestEnv && !isProduction;
|
||||
},
|
||||
instantiate: (di) => !di.inject(isProductionInjectable),
|
||||
});
|
||||
|
||||
export default isDevelopmentInjectable;
|
||||
|
||||
@ -1,18 +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 environmentVariablesInjectable from "../utils/environment-variables.injectable";
|
||||
|
||||
const isTestEnvInjectable = getInjectable({
|
||||
id: "is-test-env",
|
||||
|
||||
instantiate: (di) => {
|
||||
const { JEST_WORKER_ID: jestWorkerId } = di.inject(environmentVariablesInjectable);
|
||||
|
||||
return !!jestWorkerId;
|
||||
},
|
||||
});
|
||||
|
||||
export default isTestEnvInjectable;
|
||||
12
src/common/weblinks/migrations.ts
Normal file
12
src/common/weblinks/migrations.ts
Normal file
@ -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 { Migrations } from "conf/dist/source/types";
|
||||
import type { WeblinkStoreModel } from "./store";
|
||||
|
||||
export const weblinksStoreMigrationsInjectionToken = getInjectionToken<Migrations<WeblinkStoreModel> | undefined>({
|
||||
id: "weblinks-store-migrations-token",
|
||||
});
|
||||
@ -3,15 +3,18 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { WeblinkStore } from "./weblink-store";
|
||||
import { weblinksStoreMigrationsInjectionToken } from "./migrations";
|
||||
import { WeblinkStore } from "./store";
|
||||
|
||||
const weblinkStoreInjectable = getInjectable({
|
||||
id: "weblink-store",
|
||||
|
||||
instantiate: () => {
|
||||
instantiate: (di) => {
|
||||
WeblinkStore.resetInstance();
|
||||
|
||||
return WeblinkStore.createInstance();
|
||||
return WeblinkStore.createInstance({
|
||||
migrations: di.inject(weblinksStoreMigrationsInjectionToken),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
*/
|
||||
|
||||
import { action, comparer, observable, makeObservable } from "mobx";
|
||||
import { BaseStore } from "./base-store";
|
||||
import migrations from "../migrations/weblinks-store";
|
||||
import { BaseStore } from "../base-store";
|
||||
import * as uuid from "uuid";
|
||||
import { toJS } from "./utils";
|
||||
import { toJS } from "../utils";
|
||||
import type { Migrations } from "conf/dist/source/types";
|
||||
|
||||
export interface WeblinkData {
|
||||
id: string;
|
||||
@ -26,18 +26,22 @@ export interface WeblinkStoreModel {
|
||||
weblinks: WeblinkData[];
|
||||
}
|
||||
|
||||
export interface WeblinkStoreDependencies {
|
||||
readonly migrations: Migrations<WeblinkStoreModel> | undefined;
|
||||
}
|
||||
|
||||
export class WeblinkStore extends BaseStore<WeblinkStoreModel> {
|
||||
readonly displayName = "WeblinkStore";
|
||||
@observable weblinks: WeblinkData[] = [];
|
||||
|
||||
constructor() {
|
||||
constructor(protected readonly dependencies: WeblinkStoreDependencies) {
|
||||
super({
|
||||
configName: "lens-weblink-store",
|
||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||
syncOptions: {
|
||||
equals: comparer.structural,
|
||||
},
|
||||
migrations,
|
||||
migrations: dependencies.migrations,
|
||||
});
|
||||
makeObservable(this);
|
||||
this.load();
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { syncWeblinks } from "./weblinks";
|
||||
import weblinkStoreInjectable from "../../common/weblink-store.injectable";
|
||||
import weblinkStoreInjectable from "../../common/weblinks/store.injectable";
|
||||
import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable";
|
||||
|
||||
const syncWeblinksInjectable = getInjectable({
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { computed, observable, reaction } from "mobx";
|
||||
import type { WeblinkStore } from "../../common/weblink-store";
|
||||
import type { WeblinkStore } from "../../common/weblinks/store";
|
||||
import { WebLink } from "../../common/catalog-entities";
|
||||
import type { CatalogEntityRegistry } from "../catalog";
|
||||
import got from "got";
|
||||
|
||||
@ -101,6 +101,7 @@ import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
|
||||
import electronInjectable from "./utils/resolve-system-proxy/electron.injectable";
|
||||
import type { HotbarStore } from "../common/hotbars/store";
|
||||
import focusApplicationInjectable from "./electron-app/features/focus-application.injectable";
|
||||
import migrationLogInjectable from "./migrations/log.injectable";
|
||||
|
||||
export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) {
|
||||
const {
|
||||
@ -127,7 +128,7 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
|
||||
di.override(electronInjectable, () => ({}));
|
||||
di.override(waitUntilBundledExtensionsAreLoadedInjectable, () => async () => {});
|
||||
di.override(getRandomIdInjectable, () => () => "some-irrelevant-random-id");
|
||||
|
||||
di.override(migrationLogInjectable, () => noop);
|
||||
di.override(hotbarStoreInjectable, () => ({
|
||||
load: () => {},
|
||||
getActive: () => ({ name: "some-hotbar", items: [] }),
|
||||
|
||||
102
src/main/migrations/cluster-store/3.6.0-beta.1.injectable.ts
Normal file
102
src/main/migrations/cluster-store/3.6.0-beta.1.injectable.ts
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Move embedded kubeconfig into separate file and add reference to it to cluster settings
|
||||
// convert file path cluster icons to their base64 encoded versions
|
||||
|
||||
import { loadConfigFromString } from "../../../common/kube-helpers";
|
||||
import type { ClusterModel } from "../../../common/cluster-types";
|
||||
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 getCustomKubeConfigDirectoryInjectable from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { clusterStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
import migrationLogInjectable from "../log.injectable";
|
||||
import fsInjectable from "../../../common/fs/fs.injectable";
|
||||
import readFileSyncInjectable from "../../../common/fs/read-file-sync.injectable";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
|
||||
interface Pre360ClusterModel extends ClusterModel {
|
||||
kubeConfig?: string;
|
||||
}
|
||||
|
||||
|
||||
const clusterStoreV360Beta1MigrationInjectable = getInjectable({
|
||||
id: "cluster-store-v3.6.0-beta.1-migration",
|
||||
instantiate: (di) => {
|
||||
const migrationLog = di.inject(migrationLogInjectable);
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
|
||||
const getCustomKubeConfigDirectory = di.inject(getCustomKubeConfigDirectoryInjectable);
|
||||
const { ensureDirSync, writeFileSync } = di.inject(fsInjectable);
|
||||
const readFileSync = di.inject(readFileSyncInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
|
||||
return {
|
||||
version: "3.6.0-beta.1",
|
||||
run(store) {
|
||||
const storedClusters = (store.get("clusters") ?? []) as Pre360ClusterModel[];
|
||||
const migratedClusters: ClusterModel[] = [];
|
||||
|
||||
ensureDirSync(kubeConfigsPath);
|
||||
migrationLog("Number of clusters to migrate: ", storedClusters.length);
|
||||
|
||||
for (const clusterModel of storedClusters) {
|
||||
/**
|
||||
* migrate kubeconfig
|
||||
*/
|
||||
try {
|
||||
const absPath = getCustomKubeConfigDirectory(clusterModel.id);
|
||||
|
||||
if (!clusterModel.kubeConfig) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// take the embedded kubeconfig and dump it into a file
|
||||
writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 });
|
||||
|
||||
clusterModel.kubeConfigPath = absPath;
|
||||
delete clusterModel.kubeConfig;
|
||||
|
||||
const clusterConfigData = readFileSync(clusterModel.kubeConfigPath);
|
||||
const clusterConfig = loadConfigFromString(clusterConfigData);
|
||||
|
||||
clusterModel.contextName = clusterConfig.config.getCurrentContext();
|
||||
} catch (error) {
|
||||
migrationLog(`Failed to migrate Kubeconfig for cluster "${clusterModel.id}", removing clusterModel...`, error);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* migrate cluster icon
|
||||
*/
|
||||
try {
|
||||
if (clusterModel.preferences?.icon) {
|
||||
migrationLog(`migrating ${clusterModel.preferences.icon} for ${clusterModel.preferences.clusterName}`);
|
||||
const iconPath = clusterModel.preferences.icon.replace("store://", "");
|
||||
const fileData = readFileSync(joinPaths(userDataPath, iconPath), { asBuffer: true });
|
||||
|
||||
clusterModel.preferences.icon = `data:;base64,${fileData.toString("base64")}`;
|
||||
} else {
|
||||
delete clusterModel.preferences?.icon;
|
||||
}
|
||||
} catch (error) {
|
||||
migrationLog(`Failed to migrate cluster icon for cluster "${clusterModel.id}"`, error);
|
||||
delete clusterModel.preferences?.icon;
|
||||
}
|
||||
|
||||
migratedClusters.push(clusterModel);
|
||||
}
|
||||
|
||||
store.set("clusters", migratedClusters);
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: clusterStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterStoreV360Beta1MigrationInjectable;
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ClusterModel } from "../../../common/cluster-types";
|
||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import { isErrnoException } from "../../../common/utils";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { clusterStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
import fsInjectable from "../../../common/fs/fs.injectable";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
|
||||
interface Pre500WorkspaceStoreModel {
|
||||
workspaces: {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
const clusterStoreV500Beta10MigrationInjectable = getInjectable({
|
||||
id: "clutster-store-v5.0.0-beta.10-migration",
|
||||
instantiate: (di) => {
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const { readJsonSync } = di.inject(fsInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
|
||||
return {
|
||||
version: "5.0.0-beta.10",
|
||||
run(store) {
|
||||
try {
|
||||
const workspaceData: Pre500WorkspaceStoreModel = readJsonSync(joinPaths(userDataPath, "lens-workspace-store.json"));
|
||||
const workspaces = new Map<string, string>(); // mapping from WorkspaceId to name
|
||||
|
||||
for (const { id, name } of workspaceData.workspaces) {
|
||||
workspaces.set(id, name);
|
||||
}
|
||||
|
||||
const clusters = (store.get("clusters") ?? []) as ClusterModel[];
|
||||
|
||||
for (const cluster of clusters) {
|
||||
if (cluster.workspace) {
|
||||
const workspace = workspaces.get(cluster.workspace);
|
||||
|
||||
if (workspace) {
|
||||
(cluster.labels ??= {}).workspace = workspace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.set("clusters", clusters);
|
||||
} catch (error) {
|
||||
if (isErrnoException(error) && !(error.code === "ENOENT" && error.path?.endsWith("lens-workspace-store.json"))) {
|
||||
// ignore lens-workspace-store.json being missing
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: clusterStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterStoreV500Beta10MigrationInjectable;
|
||||
|
||||
137
src/main/migrations/cluster-store/5.0.0-beta.13.injectable.ts
Normal file
137
src/main/migrations/cluster-store/5.0.0-beta.13.injectable.ts
Normal file
@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ClusterModel, ClusterPreferences, ClusterPrometheusPreferences } from "../../../common/cluster-types";
|
||||
import { generateNewIdFor } from "../utils";
|
||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import { isDefined } from "../../../common/utils";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { clusterStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
import migrationLogInjectable from "../log.injectable";
|
||||
import fsInjectable from "../../../common/fs/fs.injectable";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
|
||||
function mergePrometheusPreferences(left: ClusterPrometheusPreferences, right: ClusterPrometheusPreferences): ClusterPrometheusPreferences {
|
||||
if (left.prometheus && left.prometheusProvider) {
|
||||
return {
|
||||
prometheus: left.prometheus,
|
||||
prometheusProvider: left.prometheusProvider,
|
||||
};
|
||||
}
|
||||
|
||||
if (right.prometheus && right.prometheusProvider) {
|
||||
return {
|
||||
prometheus: right.prometheus,
|
||||
prometheusProvider: right.prometheusProvider,
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
function mergePreferences(left: ClusterPreferences, right: ClusterPreferences): ClusterPreferences {
|
||||
return {
|
||||
terminalCWD: left.terminalCWD || right.terminalCWD || undefined,
|
||||
clusterName: left.clusterName || right.clusterName || undefined,
|
||||
iconOrder: left.iconOrder || right.iconOrder || undefined,
|
||||
icon: left.icon || right.icon || undefined,
|
||||
httpsProxy: left.httpsProxy || right.httpsProxy || undefined,
|
||||
hiddenMetrics: mergeSet(left.hiddenMetrics ?? [], right.hiddenMetrics ?? []),
|
||||
...mergePrometheusPreferences(left, right),
|
||||
};
|
||||
}
|
||||
|
||||
function mergeLabels(left: Record<string, string>, right: Record<string, string>): Record<string, string> {
|
||||
return {
|
||||
...right,
|
||||
...left,
|
||||
};
|
||||
}
|
||||
|
||||
function mergeSet(...iterables: Iterable<string | undefined>[]): string[] {
|
||||
const res = new Set<string>();
|
||||
|
||||
for (const iterable of iterables) {
|
||||
for (const val of iterable) {
|
||||
if (val) {
|
||||
res.add(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [...res];
|
||||
}
|
||||
|
||||
function mergeClusterModel(prev: ClusterModel, right: Omit<ClusterModel, "id">): ClusterModel {
|
||||
return {
|
||||
id: prev.id,
|
||||
kubeConfigPath: prev.kubeConfigPath,
|
||||
contextName: prev.contextName,
|
||||
preferences: mergePreferences(prev.preferences ?? {}, right.preferences ?? {}),
|
||||
metadata: prev.metadata,
|
||||
labels: mergeLabels(prev.labels ?? {}, right.labels ?? {}),
|
||||
accessibleNamespaces: mergeSet(prev.accessibleNamespaces ?? [], right.accessibleNamespaces ?? []),
|
||||
workspace: prev.workspace || right.workspace,
|
||||
workspaces: mergeSet([prev.workspace, right.workspace], prev.workspaces ?? [], right.workspaces ?? []),
|
||||
};
|
||||
}
|
||||
|
||||
const clusterStoreV500Beta13MigrationInjectable = getInjectable({
|
||||
id: "cluster-store-v5.0.0-beta.13-migration",
|
||||
instantiate: (di) => {
|
||||
const migrationLog = di.inject(migrationLogInjectable);
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const { moveSync, removeSync } = di.inject(fsInjectable);
|
||||
|
||||
const moveStorageFolder = ({ folder, newId, oldId }: { folder: string; newId: string; oldId: string }) => {
|
||||
const oldPath = joinPaths(folder, `${oldId}.json`);
|
||||
const newPath = joinPaths(folder, `${newId}.json`);
|
||||
|
||||
try {
|
||||
moveSync(oldPath, newPath);
|
||||
} catch (error) {
|
||||
if (String(error).includes("dest already exists")) {
|
||||
migrationLog(`Multiple old lens-local-storage files for newId=${newId}. Removing ${oldId}.json`);
|
||||
removeSync(oldPath);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
version: "5.0.0-beta.13",
|
||||
run(store) {
|
||||
const folder = joinPaths(userDataPath, "lens-local-storage");
|
||||
|
||||
const oldClusters = (store.get("clusters") ?? []) as ClusterModel[];
|
||||
const clusters = new Map<string, ClusterModel>();
|
||||
|
||||
for (const { id: oldId, ...cluster } of oldClusters) {
|
||||
const newId = generateNewIdFor(cluster);
|
||||
const newCluster = clusters.get(newId);
|
||||
|
||||
if (newCluster) {
|
||||
migrationLog(`Duplicate entries for ${newId}`, { oldId });
|
||||
clusters.set(newId, mergeClusterModel(newCluster, cluster));
|
||||
} else {
|
||||
migrationLog(`First entry for ${newId}`, { oldId });
|
||||
clusters.set(newId, {
|
||||
...cluster,
|
||||
id: newId,
|
||||
workspaces: [cluster.workspace].filter(isDefined),
|
||||
});
|
||||
moveStorageFolder({ folder, newId, oldId });
|
||||
}
|
||||
}
|
||||
|
||||
store.set("clusters", [...clusters.values()]);
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: clusterStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterStoreV500Beta13MigrationInjectable;
|
||||
|
||||
11
src/main/migrations/cluster-store/migration.ts
Normal file
11
src/main/migrations/cluster-store/migration.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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 { MigrationDeclaration } from "../declaration";
|
||||
|
||||
export const clusterStoreMigrationDeclarationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "cluster-store-migration-declaration-token",
|
||||
});
|
||||
23
src/main/migrations/cluster-store/migrations.injectable.ts
Normal file
23
src/main/migrations/cluster-store/migrations.injectable.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Cluster store migrations
|
||||
|
||||
import joinMigrationsInjectable from "../join.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { clusterStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const clusterStoreMigrationsInjectable = getInjectable({
|
||||
id: "cluster-store-migrations",
|
||||
instantiate: (di) => {
|
||||
const joinMigrations = di.inject(joinMigrationsInjectable);
|
||||
const migrationDeclarations = di.injectMany(clusterStoreMigrationDeclarationInjectionToken);
|
||||
|
||||
return joinMigrations(migrationDeclarations);
|
||||
},
|
||||
});
|
||||
|
||||
export default clusterStoreMigrationsInjectable;
|
||||
|
||||
55
src/main/migrations/cluster-store/snap.injectable.ts
Normal file
55
src/main/migrations/cluster-store/snap.injectable.ts
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Fix embedded kubeconfig paths under snap config
|
||||
|
||||
import type { ClusterModel } from "../../../common/cluster-types";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { clusterStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
import migrationLogInjectable from "../log.injectable";
|
||||
import appVersionInjectable from "../../../common/get-configuration-file-model/app-version/app-version.injectable";
|
||||
import fsInjectable from "../../../common/fs/fs.injectable";
|
||||
|
||||
const clusterStoreSnapMigrationInjectable = getInjectable({
|
||||
id: "cluster-store-snap-migration",
|
||||
instantiate: (di) => {
|
||||
const migrationLog = di.inject(migrationLogInjectable);
|
||||
const { existsSync } = di.inject(fsInjectable);
|
||||
|
||||
return {
|
||||
version: di.inject(appVersionInjectable), // Run always after upgrade
|
||||
run(store) {
|
||||
if (!process.env.SNAP) return;
|
||||
|
||||
migrationLog("Migrating embedded kubeconfig paths");
|
||||
const storedClusters = (store.get("clusters") || []) as ClusterModel[];
|
||||
|
||||
if (!storedClusters.length) return;
|
||||
|
||||
migrationLog("Number of clusters to migrate: ", storedClusters.length);
|
||||
const migratedClusters = storedClusters
|
||||
.map(cluster => {
|
||||
/**
|
||||
* replace snap version with 'current' in kubeconfig path
|
||||
*/
|
||||
if (!existsSync(cluster.kubeConfigPath)) {
|
||||
const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/");
|
||||
|
||||
cluster.kubeConfigPath = kubeconfigPath;
|
||||
}
|
||||
|
||||
return cluster;
|
||||
});
|
||||
|
||||
|
||||
store.set("clusters", migratedClusters);
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: clusterStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterStoreSnapMigrationInjectable;
|
||||
|
||||
10
src/main/migrations/declaration.ts
Normal file
10
src/main/migrations/declaration.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type Conf from "conf";
|
||||
|
||||
export interface MigrationDeclaration {
|
||||
version: string;
|
||||
run(store: Conf<Record<string, unknown>>): void;
|
||||
}
|
||||
32
src/main/migrations/hotbar-store/5.0.0-alpha.0.injectable.ts
Normal file
32
src/main/migrations/hotbar-store/5.0.0-alpha.0.injectable.ts
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
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 { hotbarStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const hotbarStoreV500Alpha0MigrationInjectable = getInjectable({
|
||||
id: "hotbar-store-v5.0.0-alpha.0-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: hotbarStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default hotbarStoreV500Alpha0MigrationInjectable;
|
||||
|
||||
29
src/main/migrations/hotbar-store/5.0.0-alpha.2.injectable.ts
Normal file
29
src/main/migrations/hotbar-store/5.0.0-alpha.2.injectable.ts
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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 * as uuid from "uuid";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { hotbarStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const hotbarStoreV500Alpha2MigrationInjectable = getInjectable({
|
||||
id: "hotbar-store-v5.0.0-alpha.2-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: hotbarStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default hotbarStoreV500Alpha2MigrationInjectable;
|
||||
|
||||
174
src/main/migrations/hotbar-store/5.0.0-beta.10.injectable.ts
Normal file
174
src/main/migrations/hotbar-store/5.0.0-beta.10.injectable.ts
Normal file
@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import fse from "fs-extra";
|
||||
import { isNull } from "lodash";
|
||||
import path from "path";
|
||||
import * as uuid from "uuid";
|
||||
import type { ClusterStoreModel } from "../../../common/cluster-store/cluster-store";
|
||||
import type { Hotbar, HotbarItem } from "../../../common/hotbars/types";
|
||||
import { defaultHotbarCells, getEmptyHotbar } from "../../../common/hotbars/types";
|
||||
import { generateNewIdFor } from "../utils";
|
||||
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 "../../../common/utils";
|
||||
|
||||
interface Pre500WorkspaceStoreModel {
|
||||
workspaces: {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
interface PartialHotbar {
|
||||
id: string;
|
||||
name: string;
|
||||
items: (null | HotbarItem)[];
|
||||
}
|
||||
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import migrationLogInjectable from "../log.injectable";
|
||||
import { hotbarStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const hotbarStoreV500Beta10MigrationInjectable = getInjectable({
|
||||
id: "hotbar-store-v5.0.0-beta.10-migration",
|
||||
instantiate: (di) => {
|
||||
const migrationLog = di.inject(migrationLogInjectable);
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
|
||||
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 di = getLegacyGlobalDiForExtensionApi();
|
||||
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
|
||||
|
||||
const { metadata: { uid, name, source }} = catalogCatalogEntity;
|
||||
|
||||
hotbar.items[0] = { entity: { uid, name, source }};
|
||||
|
||||
hotbars.push(hotbar);
|
||||
}
|
||||
|
||||
try {
|
||||
const workspaceStoreData: Pre500WorkspaceStoreModel = fse.readJsonSync(path.join(userDataPath, "lens-workspace-store.json"));
|
||||
const { clusters = [] }: ClusterStoreModel = fse.readJSONSync(path.join(userDataPath, "lens-cluster-store.json"));
|
||||
const workspaceHotbars = new Map<string, PartialHotbar>(); // mapping from WorkspaceId to HotBar
|
||||
|
||||
for (const { id, name } of workspaceStoreData.workspaces) {
|
||||
migrationLog(`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) {
|
||||
migrationLog(`Cluster ${uid} has unknown workspace ID, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
migrationLog(`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) {
|
||||
migrationLog(`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(isNull);
|
||||
|
||||
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: hotbarStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default hotbarStoreV500Beta10MigrationInjectable;
|
||||
54
src/main/migrations/hotbar-store/5.0.0-beta.5.injectable.ts
Normal file
54
src/main/migrations/hotbar-store/5.0.0-beta.5.injectable.ts
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 { hotbarStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const hotbarStoreV500Beta5MigrationInjectable = getInjectable({
|
||||
id: "hotbar-store-v5.0.0-beta.5-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: hotbarStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default hotbarStoreV500Beta5MigrationInjectable;
|
||||
|
||||
11
src/main/migrations/hotbar-store/migration.ts
Normal file
11
src/main/migrations/hotbar-store/migration.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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 { MigrationDeclaration } from "../declaration";
|
||||
|
||||
export const hotbarStoreMigrationDeclarationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "hotbar-store-migration-declaration-token",
|
||||
});
|
||||
22
src/main/migrations/hotbar-store/migrations.injectable.ts
Normal file
22
src/main/migrations/hotbar-store/migrations.injectable.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import joinMigrationsInjectable from "../join.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { hotbarStoreMigrationsInjectionToken } from "../../../common/hotbars/migrations";
|
||||
import { hotbarStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const hotbarStoreMigrationsInjectable = getInjectable({
|
||||
id: "hotbar-store-migrations",
|
||||
instantiate: (di) => {
|
||||
const joinMigrations = di.inject(joinMigrationsInjectable);
|
||||
const migrationDeclarations = di.injectMany(hotbarStoreMigrationDeclarationInjectionToken);
|
||||
|
||||
return joinMigrations(migrationDeclarations);
|
||||
},
|
||||
injectionToken: hotbarStoreMigrationsInjectionToken,
|
||||
});
|
||||
|
||||
export default hotbarStoreMigrationsInjectable;
|
||||
41
src/main/migrations/join.injectable.ts
Normal file
41
src/main/migrations/join.injectable.ts
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { Migrations } from "conf/dist/source/types";
|
||||
import { getOrInsert, iter } from "../../common/utils";
|
||||
import type { MigrationDeclaration } from "./declaration";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import migrationLogInjectable from "./log.injectable";
|
||||
|
||||
const joinMigrationsInjectable = getInjectable({
|
||||
id: "join-migrations",
|
||||
instantiate: (di) => {
|
||||
const migrationLog = di.inject(migrationLogInjectable);
|
||||
|
||||
return (declarations: MigrationDeclaration[]): Migrations<any> => {
|
||||
const migrations = new Map<string, MigrationDeclaration["run"][]>();
|
||||
|
||||
for (const decl of declarations) {
|
||||
getOrInsert(migrations, decl.version, []).push(decl.run);
|
||||
}
|
||||
|
||||
return Object.fromEntries(
|
||||
iter.map(
|
||||
migrations,
|
||||
([v, fns]) => [v, (store) => {
|
||||
migrationLog(`Running ${v} migration for ${store.path}`);
|
||||
|
||||
for (const fn of fns) {
|
||||
fn(store);
|
||||
}
|
||||
}],
|
||||
),
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default joinMigrationsInjectable;
|
||||
|
||||
19
src/main/migrations/log.injectable.ts
Normal file
19
src/main/migrations/log.injectable.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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";
|
||||
|
||||
export type MigrationLog = (message: string, ...args: any[]) => void;
|
||||
|
||||
const migrationLogInjectable = getInjectable({
|
||||
id: "migration-log",
|
||||
instantiate: (di): MigrationLog => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return (...args) => logger.info(...args);
|
||||
},
|
||||
});
|
||||
|
||||
export default migrationLogInjectable;
|
||||
21
src/main/migrations/user-store/2.1.0-beta.4.migration.ts
Normal file
21
src/main/migrations/user-store/2.1.0-beta.4.migration.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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 { userStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const userStoreV210Beta4MigrationInjectable = getInjectable({
|
||||
id: "user-store-v2.1.0-beta.4-migration",
|
||||
instantiate: () => ({
|
||||
version: "2.1.0-beta.4",
|
||||
run(store) {
|
||||
store.set("lastSeenAppVersion", "0.0.0");
|
||||
},
|
||||
}),
|
||||
injectionToken: userStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default userStoreV210Beta4MigrationInjectable;
|
||||
|
||||
30
src/main/migrations/user-store/5.0.0-alpha.3.injectable.ts
Normal file
30
src/main/migrations/user-store/5.0.0-alpha.3.injectable.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { hasTypedProperty, isObject } from "../../../common/utils";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { userStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const userStoreV500Alpha3MigrationInjectable = getInjectable({
|
||||
id: "user-store-v5.0.0-alpha.3-migration",
|
||||
instantiate: () => ({
|
||||
version: "5.0.0-alpha.3",
|
||||
run(store) {
|
||||
const preferences = store.get("preferences");
|
||||
|
||||
if (!isObject(preferences)) {
|
||||
store.delete("preferences");
|
||||
} else if (hasTypedProperty(preferences, "hiddenTableColumns", isObject)) {
|
||||
preferences.hiddenTableColumns = Object.entries(preferences.hiddenTableColumns);
|
||||
|
||||
store.set("preferences", preferences);
|
||||
}
|
||||
},
|
||||
}),
|
||||
injectionToken: userStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default userStoreV500Alpha3MigrationInjectable;
|
||||
|
||||
101
src/main/migrations/user-store/5.0.3-beta.1.injectable.ts
Normal file
101
src/main/migrations/user-store/5.0.3-beta.1.injectable.ts
Normal file
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { existsSync } from "fs";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import type { ClusterStoreModel } from "../../../common/cluster-store/cluster-store";
|
||||
import type { KubeconfigSyncEntry } from "../../../common/user-store";
|
||||
import { hasTypedProperty, isErrnoException, isLogicalChildPath } from "../../../common/utils";
|
||||
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 { getInjectable } from "@ogre-tools/injectable";
|
||||
import migrationLogInjectable from "../log.injectable";
|
||||
import { userStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
import { isObject } from "lodash";
|
||||
import readFileSyncInjectable from "../../../common/fs/read-file-sync.injectable";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
|
||||
const userStoreV503Beta1MigrationInjectable = getInjectable({
|
||||
id: "user-store-v5.0.3-beta.1-migration",
|
||||
instantiate: (di) => {
|
||||
const migrationLog = di.inject(migrationLogInjectable);
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
|
||||
const readFileSync = di.inject(readFileSyncInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
|
||||
return {
|
||||
version: "5.0.3-beta.1",
|
||||
run(store) {
|
||||
try {
|
||||
const preferences = store.get("preferences");
|
||||
|
||||
if (!isObject(preferences)) {
|
||||
store.delete("preferences");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasTypedProperty(preferences, "syncKubeconfigEntries", Array.isArray)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { syncKubeconfigEntries } = preferences;
|
||||
|
||||
const { clusters = [] }: ClusterStoreModel = JSON.parse(readFileSync(joinPaths(userDataPath, "lens-cluster-store.json"))) ?? {};
|
||||
const extensionDataDir = joinPaths(userDataPath, "extension_data");
|
||||
const syncPaths = new Set(syncKubeconfigEntries.map(s => s.filePath));
|
||||
|
||||
syncPaths.add(path.join(os.homedir(), ".kube"));
|
||||
|
||||
for (const cluster of clusters) {
|
||||
if (!cluster.kubeConfigPath) {
|
||||
continue;
|
||||
}
|
||||
const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath);
|
||||
|
||||
if (dirOfKubeconfig === kubeConfigsPath) {
|
||||
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under the stored KubeConfig folder`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (syncPaths.has(cluster.kubeConfigPath) || syncPaths.has(dirOfKubeconfig)) {
|
||||
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is already being synced`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isLogicalChildPath(extensionDataDir, cluster.kubeConfigPath)) {
|
||||
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is placed under an extension_data folder`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!existsSync(cluster.kubeConfigPath)) {
|
||||
migrationLog(`Skipping ${cluster.id} because kubeConfigPath no longer exists`);
|
||||
continue;
|
||||
}
|
||||
|
||||
migrationLog(`Adding ${cluster.kubeConfigPath} from ${cluster.id} to sync paths`);
|
||||
syncPaths.add(cluster.kubeConfigPath);
|
||||
}
|
||||
|
||||
const updatedSyncEntries: KubeconfigSyncEntry[] = [...syncPaths].map(filePath => ({ filePath }));
|
||||
|
||||
migrationLog("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: userStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default userStoreV503Beta1MigrationInjectable;
|
||||
|
||||
@ -5,13 +5,14 @@
|
||||
|
||||
import fse from "fs-extra";
|
||||
import path from "path";
|
||||
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import { isErrnoException } from "../utils";
|
||||
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import { isErrnoException } from "../../../common/utils";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { userStorePreMigrationsInjectionToken } from "../../../common/user-store/migrations";
|
||||
|
||||
const userStoreFileNameMigrationInjectable = getInjectable({
|
||||
id: "user-store-file-name-migration",
|
||||
instantiate: (di) => {
|
||||
instantiate: (di) => () => {
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const configJsonPath = path.join(userDataPath, "config.json");
|
||||
const lensUserStoreJsonPath = path.join(userDataPath, "lens-user-store.json");
|
||||
@ -30,6 +31,7 @@ const userStoreFileNameMigrationInjectable = getInjectable({
|
||||
}
|
||||
}
|
||||
},
|
||||
injectionToken: userStorePreMigrationsInjectionToken,
|
||||
});
|
||||
|
||||
export default userStoreFileNameMigrationInjectable;
|
||||
11
src/main/migrations/user-store/migration.ts
Normal file
11
src/main/migrations/user-store/migration.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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 { MigrationDeclaration } from "../declaration";
|
||||
|
||||
export const userStoreMigrationDeclarationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "user-store-migration-declaration-token",
|
||||
});
|
||||
23
src/main/migrations/user-store/migrations.injectable.ts
Normal file
23
src/main/migrations/user-store/migrations.injectable.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import joinMigrationsInjectable from "../join.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { userStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
import { userStoreMigrationsInjectionToken } from "../../../common/user-store/migrations";
|
||||
|
||||
const userStoreMigrationsInjectable = getInjectable({
|
||||
id: "user-store-migrations",
|
||||
instantiate: (di) => {
|
||||
const joinMigrations = di.inject(joinMigrationsInjectable);
|
||||
const migrationDeclarataions = di.injectMany(userStoreMigrationDeclarationInjectionToken);
|
||||
|
||||
return joinMigrations(migrationDeclarataions);
|
||||
},
|
||||
injectionToken: userStoreMigrationsInjectionToken,
|
||||
});
|
||||
|
||||
export default userStoreMigrationsInjectable;
|
||||
|
||||
42
src/main/migrations/weblinks-store/5.1.4.injectable.ts
Normal file
42
src/main/migrations/weblinks-store/5.1.4.injectable.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { docsUrl, slackUrl } from "../../../common/vars";
|
||||
import type { WeblinkData } from "../../../common/weblinks/store";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { weblinksStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
export const lensWebsiteLinkName = "Lens Website";
|
||||
export const lensDocumentationWeblinkName = "Lens Documentation";
|
||||
export const lensSlackWeblinkName = "Lens Community Slack";
|
||||
export const lensTwitterWeblinkName = "Lens on Twitter";
|
||||
export const lensBlogWeblinkName = "Lens Official Blog";
|
||||
export const kubernetesDocumentationWeblinkName = "Kubernetes Documentation";
|
||||
|
||||
const weblinksStoreV514MigrationInjectable = getInjectable({
|
||||
id: "weblinks-store-v5.1.4-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: lensWebsiteLinkName, url: "https://k8slens.dev" },
|
||||
{ id: docsUrl, name: lensDocumentationWeblinkName, url: docsUrl },
|
||||
{ id: slackUrl, name: lensSlackWeblinkName, url: slackUrl },
|
||||
{ id: "https://twitter.com/k8slens", name: lensTwitterWeblinkName, url: "https://twitter.com/k8slens" },
|
||||
{ id: "https://medium.com/k8slens", name: lensBlogWeblinkName, url: "https://medium.com/k8slens" },
|
||||
{ id: "https://kubernetes.io/docs/home/", name: kubernetesDocumentationWeblinkName, url: "https://kubernetes.io/docs/home/" },
|
||||
);
|
||||
|
||||
store.set("weblinks", weblinks);
|
||||
},
|
||||
}),
|
||||
injectionToken: weblinksStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default weblinksStoreV514MigrationInjectable;
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { kubernetesDocumentationWeblinkId, lensBlogWeblinkId, lensDocumentationWeblinkId, lensSlackWeblinkId, lensTwitterWeblinkId, lensWebsiteWeblinkId } from "../../../common/vars";
|
||||
import type { WeblinkData } from "../../../common/weblinks/store";
|
||||
import { kubernetesDocumentationWeblinkName, lensBlogWeblinkName, lensDocumentationWeblinkName, lensSlackWeblinkName, lensTwitterWeblinkName, lensWebsiteLinkName } from "./5.1.4.injectable";
|
||||
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { weblinksStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
|
||||
const weblinksStoreV545Beta1MigrationInjectable = getInjectable({
|
||||
id: "weblinks-store-v5.4.5-beta.1-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 lensWebsiteLink = weblinks.find(weblink => weblink.name === lensWebsiteLinkName);
|
||||
|
||||
if (lensWebsiteLink) {
|
||||
lensWebsiteLink.id = lensWebsiteWeblinkId;
|
||||
}
|
||||
|
||||
const lensDocumentationWeblinkLink = weblinks.find(weblink => weblink.name === lensDocumentationWeblinkName);
|
||||
|
||||
if (lensDocumentationWeblinkLink) {
|
||||
lensDocumentationWeblinkLink.id = lensDocumentationWeblinkId;
|
||||
}
|
||||
|
||||
const lensSlackWeblinkLink = weblinks.find(weblink => weblink.name === lensSlackWeblinkName);
|
||||
|
||||
if (lensSlackWeblinkLink) {
|
||||
lensSlackWeblinkLink.id = lensSlackWeblinkId;
|
||||
}
|
||||
|
||||
const lensTwitterWeblinkLink = weblinks.find(weblink => weblink.name === lensTwitterWeblinkName);
|
||||
|
||||
if (lensTwitterWeblinkLink) {
|
||||
lensTwitterWeblinkLink.id = lensTwitterWeblinkId;
|
||||
}
|
||||
|
||||
const lensBlogWeblinkLink = weblinks.find(weblink => weblink.name === lensBlogWeblinkName);
|
||||
|
||||
if (lensBlogWeblinkLink) {
|
||||
lensBlogWeblinkLink.id = lensBlogWeblinkId;
|
||||
}
|
||||
|
||||
const kubernetesDocumentationWeblinkLink = weblinks.find(weblink => weblink.name === kubernetesDocumentationWeblinkName);
|
||||
|
||||
if (kubernetesDocumentationWeblinkLink) {
|
||||
kubernetesDocumentationWeblinkLink.id = kubernetesDocumentationWeblinkId;
|
||||
}
|
||||
|
||||
store.set("weblinks", weblinks);
|
||||
},
|
||||
}),
|
||||
injectionToken: weblinksStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default weblinksStoreV545Beta1MigrationInjectable;
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { lensSlackWeblinkId, slackUrl } from "../../../common/vars";
|
||||
import type { WeblinkData } from "../../../common/weblinks/store";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { weblinksStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
import appVersionInjectable from "../../../common/get-configuration-file-model/app-version/app-version.injectable";
|
||||
|
||||
const weblinksStoreCurrentVersionMigrationInjectable = getInjectable({
|
||||
id: "weblinks-store-current-version-migration",
|
||||
instantiate: (di) => ({
|
||||
version: di.inject(appVersionInjectable), // Run always after upgrade
|
||||
run(store) {
|
||||
const weblinksRaw = store.get("weblinks");
|
||||
const weblinks = (Array.isArray(weblinksRaw) ? weblinksRaw : []) as WeblinkData[];
|
||||
const slackWeblink = weblinks.find(weblink => weblink.id === lensSlackWeblinkId);
|
||||
|
||||
if (slackWeblink) {
|
||||
slackWeblink.url = slackUrl;
|
||||
}
|
||||
|
||||
store.set("weblinks", weblinks);
|
||||
},
|
||||
}),
|
||||
injectionToken: weblinksStoreMigrationDeclarationInjectionToken,
|
||||
});
|
||||
|
||||
export default weblinksStoreCurrentVersionMigrationInjectable;
|
||||
|
||||
11
src/main/migrations/weblinks-store/migration.ts
Normal file
11
src/main/migrations/weblinks-store/migration.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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 { MigrationDeclaration } from "../declaration";
|
||||
|
||||
export const weblinksStoreMigrationDeclarationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||
id: "weblinks-store-migration-declaration-token",
|
||||
});
|
||||
23
src/main/migrations/weblinks-store/migrations.injectable.ts
Normal file
23
src/main/migrations/weblinks-store/migrations.injectable.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import joinMigrationsInjectable from "../join.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { weblinksStoreMigrationDeclarationInjectionToken } from "./migration";
|
||||
import { weblinksStoreMigrationsInjectionToken } from "../../../common/weblinks/migrations";
|
||||
|
||||
const weblinksStoreMigrationsInjectable = getInjectable({
|
||||
id: "weblinks-store-migrations",
|
||||
instantiate: (di) => {
|
||||
const joinMigrations = di.inject(joinMigrationsInjectable);
|
||||
const migrationDeclarations = di.injectMany(weblinksStoreMigrationDeclarationInjectionToken);
|
||||
|
||||
return joinMigrations(migrationDeclarations);
|
||||
},
|
||||
injectionToken: weblinksStoreMigrationsInjectionToken,
|
||||
});
|
||||
|
||||
export default weblinksStoreMigrationsInjectable;
|
||||
|
||||
@ -1,90 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Move embedded kubeconfig into separate file and add reference to it to cluster settings
|
||||
// convert file path cluster icons to their base64 encoded versions
|
||||
|
||||
import path from "path";
|
||||
import fse from "fs-extra";
|
||||
import { loadConfigFromFileSync } from "../../common/kube-helpers";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
import { migrationLog } from "../helpers";
|
||||
import type { ClusterModel } from "../../common/cluster-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 directoryForKubeConfigsInjectable
|
||||
from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||
import getCustomKubeConfigDirectoryInjectable
|
||||
from "../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable";
|
||||
|
||||
interface Pre360ClusterModel extends ClusterModel {
|
||||
kubeConfig?: string;
|
||||
}
|
||||
|
||||
export default {
|
||||
version: "3.6.0-beta.1",
|
||||
run(store) {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
|
||||
const getCustomKubeConfigDirectory = di.inject(getCustomKubeConfigDirectoryInjectable);
|
||||
|
||||
const storedClusters: Pre360ClusterModel[] = store.get("clusters") ?? [];
|
||||
const migratedClusters: ClusterModel[] = [];
|
||||
|
||||
fse.ensureDirSync(kubeConfigsPath);
|
||||
|
||||
migrationLog("Number of clusters to migrate: ", storedClusters.length);
|
||||
|
||||
for (const clusterModel of storedClusters) {
|
||||
/**
|
||||
* migrate kubeconfig
|
||||
*/
|
||||
try {
|
||||
const absPath = getCustomKubeConfigDirectory(clusterModel.id);
|
||||
|
||||
if (!clusterModel.kubeConfig) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// take the embedded kubeconfig and dump it into a file
|
||||
fse.writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 });
|
||||
|
||||
clusterModel.kubeConfigPath = absPath;
|
||||
clusterModel.contextName = loadConfigFromFileSync(clusterModel.kubeConfigPath).config.getCurrentContext();
|
||||
delete clusterModel.kubeConfig;
|
||||
|
||||
} catch (error) {
|
||||
migrationLog(`Failed to migrate Kubeconfig for cluster "${clusterModel.id}", removing clusterModel...`, error);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* migrate cluster icon
|
||||
*/
|
||||
try {
|
||||
if (clusterModel.preferences?.icon) {
|
||||
migrationLog(`migrating ${clusterModel.preferences.icon} for ${clusterModel.preferences.clusterName}`);
|
||||
const iconPath = clusterModel.preferences.icon.replace("store://", "");
|
||||
const fileData = fse.readFileSync(path.join(userDataPath, iconPath));
|
||||
|
||||
clusterModel.preferences.icon = `data:;base64,${fileData.toString("base64")}`;
|
||||
} else {
|
||||
delete clusterModel.preferences?.icon;
|
||||
}
|
||||
} catch (error) {
|
||||
migrationLog(`Failed to migrate cluster icon for cluster "${clusterModel.id}"`, error);
|
||||
delete clusterModel.preferences?.icon;
|
||||
}
|
||||
|
||||
migratedClusters.push(clusterModel);
|
||||
}
|
||||
|
||||
store.set("clusters", migratedClusters);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import path from "path";
|
||||
import fse from "fs-extra";
|
||||
import type { ClusterModel } from "../../common/cluster-types";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
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 { isErrnoException } from "../../common/utils";
|
||||
|
||||
interface Pre500WorkspaceStoreModel {
|
||||
workspaces: {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export default {
|
||||
version: "5.0.0-beta.10",
|
||||
run(store) {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
|
||||
try {
|
||||
const workspaceData: Pre500WorkspaceStoreModel = fse.readJsonSync(path.join(userDataPath, "lens-workspace-store.json"));
|
||||
const workspaces = new Map<string, string>(); // mapping from WorkspaceId to name
|
||||
|
||||
for (const { id, name } of workspaceData.workspaces) {
|
||||
workspaces.set(id, name);
|
||||
}
|
||||
|
||||
const clusters: ClusterModel[] = store.get("clusters") ?? [];
|
||||
|
||||
for (const cluster of clusters) {
|
||||
if (cluster.workspace) {
|
||||
const workspace = workspaces.get(cluster.workspace);
|
||||
|
||||
if (workspace) {
|
||||
(cluster.labels ??= {}).workspace = workspace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store.set("clusters", clusters);
|
||||
} catch (error) {
|
||||
if (isErrnoException(error) && !(error.code === "ENOENT" && error.path?.endsWith("lens-workspace-store.json"))) {
|
||||
// ignore lens-workspace-store.json being missing
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,128 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ClusterModel, ClusterPreferences, ClusterPrometheusPreferences } from "../../common/cluster-types";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
import { migrationLog } from "../helpers";
|
||||
import { generateNewIdFor } from "../utils";
|
||||
import path from "path";
|
||||
import { moveSync, removeSync } from "fs-extra";
|
||||
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 { isDefined } from "../../common/utils";
|
||||
|
||||
function mergePrometheusPreferences(left: ClusterPrometheusPreferences, right: ClusterPrometheusPreferences): ClusterPrometheusPreferences {
|
||||
if (left.prometheus && left.prometheusProvider) {
|
||||
return {
|
||||
prometheus: left.prometheus,
|
||||
prometheusProvider: left.prometheusProvider,
|
||||
};
|
||||
}
|
||||
|
||||
if (right.prometheus && right.prometheusProvider) {
|
||||
return {
|
||||
prometheus: right.prometheus,
|
||||
prometheusProvider: right.prometheusProvider,
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
function mergePreferences(left: ClusterPreferences, right: ClusterPreferences): ClusterPreferences {
|
||||
return {
|
||||
terminalCWD: left.terminalCWD || right.terminalCWD || undefined,
|
||||
clusterName: left.clusterName || right.clusterName || undefined,
|
||||
iconOrder: left.iconOrder || right.iconOrder || undefined,
|
||||
icon: left.icon || right.icon || undefined,
|
||||
httpsProxy: left.httpsProxy || right.httpsProxy || undefined,
|
||||
hiddenMetrics: mergeSet(left.hiddenMetrics ?? [], right.hiddenMetrics ?? []),
|
||||
...mergePrometheusPreferences(left, right),
|
||||
};
|
||||
}
|
||||
|
||||
function mergeLabels(left: Record<string, string>, right: Record<string, string>): Record<string, string> {
|
||||
return {
|
||||
...right,
|
||||
...left,
|
||||
};
|
||||
}
|
||||
|
||||
function mergeSet(...iterables: Iterable<string | undefined>[]): string[] {
|
||||
const res = new Set<string>();
|
||||
|
||||
for (const iterable of iterables) {
|
||||
for (const val of iterable) {
|
||||
if (val) {
|
||||
res.add(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [...res];
|
||||
}
|
||||
|
||||
function mergeClusterModel(prev: ClusterModel, right: Omit<ClusterModel, "id">): ClusterModel {
|
||||
return {
|
||||
id: prev.id,
|
||||
kubeConfigPath: prev.kubeConfigPath,
|
||||
contextName: prev.contextName,
|
||||
preferences: mergePreferences(prev.preferences ?? {}, right.preferences ?? {}),
|
||||
metadata: prev.metadata,
|
||||
labels: mergeLabels(prev.labels ?? {}, right.labels ?? {}),
|
||||
accessibleNamespaces: mergeSet(prev.accessibleNamespaces ?? [], right.accessibleNamespaces ?? []),
|
||||
workspace: prev.workspace || right.workspace,
|
||||
workspaces: mergeSet([prev.workspace, right.workspace], prev.workspaces ?? [], right.workspaces ?? []),
|
||||
};
|
||||
}
|
||||
|
||||
function moveStorageFolder({ folder, newId, oldId }: { folder: string; newId: string; oldId: string }): void {
|
||||
const oldPath = path.resolve(folder, `${oldId}.json`);
|
||||
const newPath = path.resolve(folder, `${newId}.json`);
|
||||
|
||||
try {
|
||||
moveSync(oldPath, newPath);
|
||||
} catch (error) {
|
||||
if (String(error).includes("dest already exists")) {
|
||||
migrationLog(`Multiple old lens-local-storage files for newId=${newId}. Removing ${oldId}.json`);
|
||||
removeSync(oldPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
version: "5.0.0-beta.13",
|
||||
run(store) {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
|
||||
const folder = path.resolve(userDataPath, "lens-local-storage");
|
||||
|
||||
const oldClusters: ClusterModel[] = store.get("clusters") ?? [];
|
||||
const clusters = new Map<string, ClusterModel>();
|
||||
|
||||
for (const { id: oldId, ...cluster } of oldClusters) {
|
||||
const newId = generateNewIdFor(cluster);
|
||||
const newCluster = clusters.get(newId);
|
||||
|
||||
if (newCluster) {
|
||||
migrationLog(`Duplicate entries for ${newId}`, { oldId });
|
||||
clusters.set(newId, mergeClusterModel(newCluster, cluster));
|
||||
} else {
|
||||
migrationLog(`First entry for ${newId}`, { oldId });
|
||||
clusters.set(newId, {
|
||||
...cluster,
|
||||
id: newId,
|
||||
workspaces: [cluster.workspace].filter(isDefined),
|
||||
});
|
||||
moveStorageFolder({ folder, newId, oldId });
|
||||
}
|
||||
}
|
||||
|
||||
store.set("clusters", [...clusters.values()]);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Cluster store migrations
|
||||
|
||||
import { joinMigrations } from "../helpers";
|
||||
|
||||
import version360Beta1 from "./3.6.0-beta.1";
|
||||
import version500Beta10 from "./5.0.0-beta.10";
|
||||
import version500Beta13 from "./5.0.0-beta.13";
|
||||
import snap from "./snap";
|
||||
|
||||
export default joinMigrations(
|
||||
version360Beta1,
|
||||
version500Beta10,
|
||||
version500Beta13,
|
||||
snap,
|
||||
);
|
||||
@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Fix embedded kubeconfig paths under snap config
|
||||
|
||||
import type { ClusterModel } from "../../common/cluster-types";
|
||||
import { getAppVersion } from "../../common/utils/app-version";
|
||||
import fs from "fs";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
import { migrationLog } from "../helpers";
|
||||
|
||||
export default {
|
||||
version: getAppVersion(), // Run always after upgrade
|
||||
run(store) {
|
||||
if (!process.env["SNAP"]) return;
|
||||
|
||||
migrationLog("Migrating embedded kubeconfig paths");
|
||||
const storedClusters: ClusterModel[] = store.get("clusters") || [];
|
||||
|
||||
if (!storedClusters.length) return;
|
||||
|
||||
migrationLog("Number of clusters to migrate: ", storedClusters.length);
|
||||
const migratedClusters = storedClusters
|
||||
.map(cluster => {
|
||||
/**
|
||||
* replace snap version with 'current' in kubeconfig path
|
||||
*/
|
||||
if (!fs.existsSync(cluster.kubeConfigPath)) {
|
||||
const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/");
|
||||
|
||||
cluster.kubeConfigPath = kubeconfigPath;
|
||||
}
|
||||
|
||||
return cluster;
|
||||
});
|
||||
|
||||
|
||||
store.set("clusters", migratedClusters);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type Conf from "conf";
|
||||
import type { Migrations } from "conf/dist/source/types";
|
||||
import { getOrInsert, iter } from "../common/utils";
|
||||
import { isTestEnv } from "../common/vars";
|
||||
|
||||
export function migrationLog(...args: any[]) {
|
||||
if (!isTestEnv) {
|
||||
console.log(...args);
|
||||
}
|
||||
}
|
||||
|
||||
export interface MigrationDeclaration {
|
||||
version: string;
|
||||
run(store: Conf<any>): void;
|
||||
}
|
||||
|
||||
export function joinMigrations(...declarations: MigrationDeclaration[]): Migrations<any> {
|
||||
const migrations = new Map<string, MigrationDeclaration["run"][]>();
|
||||
|
||||
for (const decl of declarations) {
|
||||
getOrInsert(migrations, decl.version, []).push(decl.run);
|
||||
}
|
||||
|
||||
return Object.fromEntries(
|
||||
iter.map(
|
||||
migrations,
|
||||
([v, fns]) => [v, (store: Conf<any>) => {
|
||||
migrationLog(`Running ${v} migration for ${store.path}`);
|
||||
|
||||
for (const fn of fns) {
|
||||
fn(store);
|
||||
}
|
||||
}],
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -1,25 +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 { MigrationDeclaration } from "../helpers";
|
||||
import { getEmptyHotbar } from "../../common/hotbars/types";
|
||||
import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import catalogCatalogEntityInjectable from "../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
|
||||
|
||||
export default {
|
||||
version: "5.0.0-alpha.0",
|
||||
run(store) {
|
||||
const hotbar = getEmptyHotbar("default");
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
|
||||
|
||||
const { metadata: { uid, name, source }} = catalogCatalogEntity;
|
||||
|
||||
hotbar.items[0] = { entity: { uid, name, source }};
|
||||
|
||||
store.set("hotbars", [hotbar]);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,22 +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 type { MigrationDeclaration } from "../helpers";
|
||||
|
||||
export default {
|
||||
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,
|
||||
})));
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,165 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import fse from "fs-extra";
|
||||
import { isNull } from "lodash";
|
||||
import path from "path";
|
||||
import * as uuid from "uuid";
|
||||
import type { ClusterStoreModel } from "../../common/cluster-store/cluster-store";
|
||||
import type { Hotbar, HotbarItem } from "../../common/hotbars/types";
|
||||
import { defaultHotbarCells, getEmptyHotbar } from "../../common/hotbars/types";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
import { migrationLog } from "../helpers";
|
||||
import { generateNewIdFor } from "../utils";
|
||||
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 "../../common/utils";
|
||||
|
||||
interface Pre500WorkspaceStoreModel {
|
||||
workspaces: {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
interface PartialHotbar {
|
||||
id: string;
|
||||
name: string;
|
||||
items: (null | HotbarItem)[];
|
||||
}
|
||||
|
||||
export default {
|
||||
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") : [];
|
||||
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
|
||||
// Hotbars might be empty, if some of the previous migrations weren't run
|
||||
if (hotbars.length === 0) {
|
||||
const hotbar = getEmptyHotbar("default");
|
||||
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
|
||||
|
||||
const { metadata: { uid, name, source }} = catalogCatalogEntity;
|
||||
|
||||
hotbar.items[0] = { entity: { uid, name, source }};
|
||||
|
||||
hotbars.push(hotbar);
|
||||
}
|
||||
|
||||
try {
|
||||
const workspaceStoreData: Pre500WorkspaceStoreModel = fse.readJsonSync(path.join(userDataPath, "lens-workspace-store.json"));
|
||||
const { clusters = [] }: ClusterStoreModel = fse.readJSONSync(path.join(userDataPath, "lens-cluster-store.json"));
|
||||
const workspaceHotbars = new Map<string, PartialHotbar>(); // mapping from WorkspaceId to HotBar
|
||||
|
||||
for (const { id, name } of workspaceStoreData.workspaces) {
|
||||
migrationLog(`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) {
|
||||
migrationLog(`Cluster ${uid} has unknown workspace ID, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
migrationLog(`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) {
|
||||
migrationLog(`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(isNull);
|
||||
|
||||
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);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,45 +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 { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||
import catalogEntityRegistryInjectable from "../../main/catalog/entity-registry.injectable";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
|
||||
export default {
|
||||
version: "5.0.0-beta.5",
|
||||
run(store) {
|
||||
const rawHotbars = store.get("hotbars");
|
||||
const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars : [];
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||
|
||||
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);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Hotbar store migrations
|
||||
|
||||
import { joinMigrations } from "../helpers";
|
||||
|
||||
import version500alpha0 from "./5.0.0-alpha.0";
|
||||
import version500alpha2 from "./5.0.0-alpha.2";
|
||||
import version500beta5 from "./5.0.0-beta.5";
|
||||
import version500beta10 from "./5.0.0-beta.10";
|
||||
|
||||
export default joinMigrations(
|
||||
version500alpha0,
|
||||
version500alpha2,
|
||||
version500beta5,
|
||||
version500beta10,
|
||||
);
|
||||
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// Add / reset "lastSeenAppVersion"
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
|
||||
export default {
|
||||
version: "2.1.0-beta.4",
|
||||
run(store) {
|
||||
store.set("lastSeenAppVersion", "0.0.0");
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,23 +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 type { MigrationDeclaration } from "../helpers";
|
||||
|
||||
export default {
|
||||
version: "5.0.0-alpha.3",
|
||||
run(store) {
|
||||
const preferences = store.get("preferences");
|
||||
const oldHiddenTableColumns: Record<string, string[]> = preferences?.hiddenTableColumns;
|
||||
|
||||
if (!oldHiddenTableColumns) {
|
||||
return;
|
||||
}
|
||||
|
||||
preferences.hiddenTableColumns = Object.entries(oldHiddenTableColumns);
|
||||
|
||||
store.set("preferences", preferences);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,78 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import type { ClusterStoreModel } from "../../common/cluster-store/cluster-store";
|
||||
import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../common/user-store";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
import { migrationLog } from "../helpers";
|
||||
import { isErrnoException, isLogicalChildPath } from "../../common/utils";
|
||||
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 directoryForKubeConfigsInjectable
|
||||
from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||
|
||||
export default {
|
||||
version: "5.0.3-beta.1",
|
||||
run(store) {
|
||||
try {
|
||||
const { syncKubeconfigEntries = [], ...preferences }: UserPreferencesModel = store.get("preferences") ?? {};
|
||||
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const userDataPath = di.inject(directoryForUserDataInjectable);
|
||||
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
|
||||
|
||||
const { clusters = [] }: ClusterStoreModel = JSON.parse(readFileSync(path.resolve(userDataPath, "lens-cluster-store.json"), "utf-8")) ?? {};
|
||||
const extensionDataDir = path.resolve(userDataPath, "extension_data");
|
||||
const syncPaths = new Set(syncKubeconfigEntries.map(s => s.filePath));
|
||||
|
||||
syncPaths.add(path.join(os.homedir(), ".kube"));
|
||||
|
||||
for (const cluster of clusters) {
|
||||
if (!cluster.kubeConfigPath) {
|
||||
continue;
|
||||
}
|
||||
const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath);
|
||||
|
||||
if (dirOfKubeconfig === kubeConfigsPath) {
|
||||
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under the stored KubeConfig folder`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (syncPaths.has(cluster.kubeConfigPath) || syncPaths.has(dirOfKubeconfig)) {
|
||||
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is already being synced`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isLogicalChildPath(extensionDataDir, cluster.kubeConfigPath)) {
|
||||
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is placed under an extension_data folder`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!existsSync(cluster.kubeConfigPath)) {
|
||||
migrationLog(`Skipping ${cluster.id} because kubeConfigPath no longer exists`);
|
||||
continue;
|
||||
}
|
||||
|
||||
migrationLog(`Adding ${cluster.kubeConfigPath} from ${cluster.id} to sync paths`);
|
||||
syncPaths.add(cluster.kubeConfigPath);
|
||||
}
|
||||
|
||||
const updatedSyncEntries: KubeconfigSyncEntry[] = [...syncPaths].map(filePath => ({ filePath }));
|
||||
|
||||
migrationLog("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;
|
||||
}
|
||||
}
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
// User store migrations
|
||||
|
||||
import { joinMigrations } from "../helpers";
|
||||
|
||||
import version210Beta4 from "./2.1.0-beta.4";
|
||||
import version500Alpha3 from "./5.0.0-alpha.3";
|
||||
import version503Beta1 from "./5.0.3-beta.1";
|
||||
|
||||
export default joinMigrations(
|
||||
version210Beta4,
|
||||
version500Alpha3,
|
||||
version503Beta1,
|
||||
);
|
||||
@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { docsUrl, slackUrl } from "../../common/vars";
|
||||
import type { WeblinkData } from "../../common/weblink-store";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
|
||||
export const lensWebsiteLinkName = "Lens Website";
|
||||
export const lensDocumentationWeblinkName = "Lens Documentation";
|
||||
export const lensSlackWeblinkName = "Lens Community Slack";
|
||||
export const lensTwitterWeblinkName = "Lens on Twitter";
|
||||
export const lensBlogWeblinkName = "Lens Official Blog";
|
||||
export const kubernetesDocumentationWeblinkName = "Kubernetes Documentation";
|
||||
|
||||
export default {
|
||||
version: "5.1.4",
|
||||
run(store) {
|
||||
const weblinksRaw: any = store.get("weblinks");
|
||||
const weblinks = (Array.isArray(weblinksRaw) ? weblinksRaw : []) as WeblinkData[];
|
||||
|
||||
weblinks.push(
|
||||
{ id: "https://k8slens.dev", name: lensWebsiteLinkName, url: "https://k8slens.dev" },
|
||||
{ id: docsUrl, name: lensDocumentationWeblinkName, url: docsUrl },
|
||||
{ id: slackUrl, name: lensSlackWeblinkName, url: slackUrl },
|
||||
{ id: "https://twitter.com/k8slens", name: lensTwitterWeblinkName, url: "https://twitter.com/k8slens" },
|
||||
{ id: "https://medium.com/k8slens", name: lensBlogWeblinkName, url: "https://medium.com/k8slens" },
|
||||
{ id: "https://kubernetes.io/docs/home/", name: kubernetesDocumentationWeblinkName, url: "https://kubernetes.io/docs/home/" },
|
||||
);
|
||||
|
||||
store.set("weblinks", weblinks);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { kubernetesDocumentationWeblinkId, lensBlogWeblinkId, lensDocumentationWeblinkId, lensSlackWeblinkId, lensTwitterWeblinkId, lensWebsiteWeblinkId } from "../../common/vars";
|
||||
import type { WeblinkData } from "../../common/weblink-store";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
import { kubernetesDocumentationWeblinkName, lensBlogWeblinkName, lensDocumentationWeblinkName, lensSlackWeblinkName, lensTwitterWeblinkName, lensWebsiteLinkName } from "./5.1.4";
|
||||
|
||||
export default {
|
||||
version: "5.4.5-beta.1 || >=5.5.0-alpha.0",
|
||||
run(store) {
|
||||
const weblinksRaw: any = store.get("weblinks");
|
||||
const weblinks = (Array.isArray(weblinksRaw) ? weblinksRaw : []) as WeblinkData[];
|
||||
|
||||
const lensWebsiteLink = weblinks.find(weblink => weblink.name === lensWebsiteLinkName);
|
||||
|
||||
if (lensWebsiteLink) {
|
||||
lensWebsiteLink.id = lensWebsiteWeblinkId;
|
||||
}
|
||||
|
||||
const lensDocumentationWeblinkLink = weblinks.find(weblink => weblink.name === lensDocumentationWeblinkName);
|
||||
|
||||
if (lensDocumentationWeblinkLink) {
|
||||
lensDocumentationWeblinkLink.id = lensDocumentationWeblinkId;
|
||||
}
|
||||
|
||||
const lensSlackWeblinkLink = weblinks.find(weblink => weblink.name === lensSlackWeblinkName);
|
||||
|
||||
if (lensSlackWeblinkLink) {
|
||||
lensSlackWeblinkLink.id = lensSlackWeblinkId;
|
||||
}
|
||||
|
||||
const lensTwitterWeblinkLink = weblinks.find(weblink => weblink.name === lensTwitterWeblinkName);
|
||||
|
||||
if (lensTwitterWeblinkLink) {
|
||||
lensTwitterWeblinkLink.id = lensTwitterWeblinkId;
|
||||
}
|
||||
|
||||
const lensBlogWeblinkLink = weblinks.find(weblink => weblink.name === lensBlogWeblinkName);
|
||||
|
||||
if (lensBlogWeblinkLink) {
|
||||
lensBlogWeblinkLink.id = lensBlogWeblinkId;
|
||||
}
|
||||
|
||||
const kubernetesDocumentationWeblinkLink = weblinks.find(weblink => weblink.name === kubernetesDocumentationWeblinkName);
|
||||
|
||||
if (kubernetesDocumentationWeblinkLink) {
|
||||
kubernetesDocumentationWeblinkLink.id = kubernetesDocumentationWeblinkId;
|
||||
}
|
||||
|
||||
store.set("weblinks", weblinks);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,24 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getAppVersion } from "../../common/utils";
|
||||
import { lensSlackWeblinkId, slackUrl } from "../../common/vars";
|
||||
import type { WeblinkData } from "../../common/weblink-store";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
|
||||
export default {
|
||||
version: getAppVersion(), // Run always after upgrade
|
||||
run(store) {
|
||||
const weblinksRaw: any = store.get("weblinks");
|
||||
const weblinks = (Array.isArray(weblinksRaw) ? weblinksRaw : []) as WeblinkData[];
|
||||
const slackWeblink = weblinks.find(weblink => weblink.id === lensSlackWeblinkId);
|
||||
|
||||
if (slackWeblink) {
|
||||
slackWeblink.url = slackUrl;
|
||||
}
|
||||
|
||||
store.set("weblinks", weblinks);
|
||||
},
|
||||
} as MigrationDeclaration;
|
||||
@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { joinMigrations } from "../helpers";
|
||||
|
||||
import version514 from "./5.1.4";
|
||||
import version545Beta1 from "./5.4.5-beta.1";
|
||||
import currentVersion from "./currentVersion";
|
||||
|
||||
export default joinMigrations(
|
||||
version514,
|
||||
version545Beta1,
|
||||
currentVersion,
|
||||
);
|
||||
@ -19,7 +19,6 @@ 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 { initializeSentryReporting } from "../common/sentry";
|
||||
import { registerCustomThemes } from "./components/monaco-editor";
|
||||
import { getDi } from "./getDi";
|
||||
@ -46,6 +45,7 @@ import kubernetesClusterCategoryInjectable from "../common/catalog/categories/ku
|
||||
import autoRegistrationInjectable from "../common/k8s-api/api-manager/auto-registration.injectable";
|
||||
import assert from "assert";
|
||||
import startFrameInjectable from "./start-frame/start-frame.injectable";
|
||||
import weblinkStoreInjectable from "../common/weblinks/store.injectable";
|
||||
|
||||
configurePackages(); // global packages
|
||||
registerCustomThemes(); // monaco editor themes
|
||||
@ -141,7 +141,7 @@ export async function bootstrap(di: DiContainer) {
|
||||
// TODO: Remove temporal dependencies
|
||||
di.inject(themeStoreInjectable);
|
||||
|
||||
WeblinkStore.createInstance();
|
||||
di.inject(weblinkStoreInjectable);
|
||||
|
||||
const extensionInstallationStateStore = di.inject(extensionInstallationStateStoreInjectable);
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ 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 { WeblinkStore } from "../../../common/weblinks/store";
|
||||
import { computed, makeObservable, observable } from "mobx";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import commandOverlayInjectable from "../command-palette/command-overlay.injectable";
|
||||
@ -64,7 +64,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">
|
||||
|
||||
@ -101,7 +101,6 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
|
||||
di.override(startTopbarStateSyncInjectable, () => ({
|
||||
run: () => {},
|
||||
}));
|
||||
|
||||
di.override(terminalSpawningPoolInjectable, () => document.createElement("div"));
|
||||
di.override(hostedClusterIdInjectable, () => undefined);
|
||||
|
||||
|
||||
14
src/renderer/migrations/cluster-store.injectable.ts
Normal file
14
src/renderer/migrations/cluster-store.injectable.ts
Normal file
@ -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 { clusterStoreMigrationsInjectionToken } from "../../common/cluster-store/migrations";
|
||||
|
||||
const clusterStoreMigrationsInjectable = getInjectable({
|
||||
id: "cluster-store-migrations",
|
||||
instantiate: () => undefined,
|
||||
injectionToken: clusterStoreMigrationsInjectionToken,
|
||||
});
|
||||
|
||||
export default clusterStoreMigrationsInjectable;
|
||||
14
src/renderer/migrations/hotbar-store.injectable.ts
Normal file
14
src/renderer/migrations/hotbar-store.injectable.ts
Normal file
@ -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 { hotbarStoreMigrationsInjectionToken } from "../../common/hotbars/migrations";
|
||||
|
||||
const hotbarStoreMigrationsInjectable = getInjectable({
|
||||
id: "hotbar-store-migrations",
|
||||
instantiate: () => undefined,
|
||||
injectionToken: hotbarStoreMigrationsInjectionToken,
|
||||
});
|
||||
|
||||
export default hotbarStoreMigrationsInjectable;
|
||||
14
src/renderer/migrations/user-store.injectable.ts
Normal file
14
src/renderer/migrations/user-store.injectable.ts
Normal file
@ -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 { userStoreMigrationsInjectionToken } from "../../common/user-store/migrations";
|
||||
|
||||
const userStoreMigrationsInjectable = getInjectable({
|
||||
id: "user-store-migrations",
|
||||
instantiate: () => undefined,
|
||||
injectionToken: userStoreMigrationsInjectionToken,
|
||||
});
|
||||
|
||||
export default userStoreMigrationsInjectable;
|
||||
14
src/renderer/migrations/weblinks-store.injectable.ts
Normal file
14
src/renderer/migrations/weblinks-store.injectable.ts
Normal file
@ -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 { weblinksStoreMigrationsInjectionToken } from "../../common/weblinks/migrations";
|
||||
|
||||
const weblinksStoreMigrationsInjectable = getInjectable({
|
||||
id: "weblinks-store-migrations",
|
||||
instantiate: () => undefined,
|
||||
injectionToken: weblinksStoreMigrationsInjectionToken,
|
||||
});
|
||||
|
||||
export default weblinksStoreMigrationsInjectable;
|
||||
@ -8,7 +8,6 @@
|
||||
import { comparer, reaction, toJS, when } from "mobx";
|
||||
import type { StorageLayer } from "../storageHelper";
|
||||
import { StorageHelper } from "../storageHelper";
|
||||
import { isTestEnv } from "../../../common/vars";
|
||||
import type { JsonObject, JsonValue } from "type-fest";
|
||||
import type { Logger } from "../../../common/logger";
|
||||
import type { GetAbsolutePath } from "../../../common/path/get-absolute-path.injectable";
|
||||
@ -52,10 +51,7 @@ export const createStorage = ({
|
||||
} catch {
|
||||
// do nothing
|
||||
} finally {
|
||||
if (!isTestEnv) {
|
||||
logger.info(`${logPrefix} loading finished for ${filePath}`);
|
||||
}
|
||||
|
||||
logger.debug(`${logPrefix} loading finished for ${filePath}`);
|
||||
storage.loaded = true;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user