1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Switch HotbarStore to injectable migrations

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-11-30 15:41:14 -05:00
parent ad814ebdf6
commit 1aa3e46262
12 changed files with 305 additions and 280 deletions

View 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 "../base-store/migrations.injectable";
export const hotbarStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
id: "hotbar-store-migration-token",
});

View File

@ -9,6 +9,8 @@ import loggerInjectable from "../logger.injectable";
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable"; import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
import storeMigrationsInjectable from "../base-store/migrations.injectable";
import { hotbarStoreMigrationInjectionToken } from "./migrations-token";
const hotbarStoreInjectable = getInjectable({ const hotbarStoreInjectable = getInjectable({
id: "hotbar-store", id: "hotbar-store",
@ -19,6 +21,7 @@ const hotbarStoreInjectable = getInjectable({
directoryForUserData: di.inject(directoryForUserDataInjectable), directoryForUserData: di.inject(directoryForUserDataInjectable),
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
storeMigrationVersion: di.inject(storeMigrationVersionInjectable), storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
migrations: di.inject(storeMigrationsInjectable, hotbarStoreMigrationInjectionToken),
}), }),
}); });

View File

@ -6,7 +6,6 @@
import { action, comparer, observable, makeObservable, computed } from "mobx"; import { action, comparer, observable, makeObservable, computed } from "mobx";
import type { BaseStoreDependencies } from "../base-store/base-store"; import type { BaseStoreDependencies } from "../base-store/base-store";
import { BaseStore } from "../base-store/base-store"; import { BaseStore } from "../base-store/base-store";
import migrations from "../../migrations/hotbar-store";
import { toJS } from "../utils"; import { toJS } from "../utils";
import type { CatalogEntity } from "../catalog"; import type { CatalogEntity } from "../catalog";
import { broadcastMessage } from "../ipc"; import { broadcastMessage } from "../ipc";
@ -39,7 +38,6 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
syncOptions: { syncOptions: {
equals: comparer.structural, equals: comparer.structural,
}, },
migrations,
}); });
makeObservable(this); makeObservable(this);

View File

@ -0,0 +1,34 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// Cleans up a store that had the state related data stored
import { getEmptyHotbar } from "../../../common/hotbars/types";
import catalogCatalogEntityInjectable from "../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token";
const v500Alpha0HotbarStoreMigrationInjectable = getInjectable({
id: "v5.0.0-alpha.0-hotbar-store-migration",
instantiate: (di) => {
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
return {
version: "5.0.0-alpha.0",
run(store) {
const hotbar = getEmptyHotbar("default");
const { metadata: { uid, name, source }} = catalogCatalogEntity;
hotbar.items[0] = { entity: { uid, name, source }};
store.set("hotbars", [hotbar]);
},
};
},
injectionToken: hotbarStoreMigrationInjectionToken,
});
export default v500Alpha0HotbarStoreMigrationInjectable;

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// Cleans up a store that had the state related data stored
import type { Hotbar } from "../../../common/hotbars/types";
import * as uuid from "uuid";
import { getInjectable } from "@ogre-tools/injectable";
import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token";
const v500Alpha2HotbarStoreMigrationInjectable = getInjectable({
id: "v5.0.0-alpha.2-hotbar-store-migration",
instantiate: () => ({
version: "5.0.0-alpha.2",
run(store) {
const rawHotbars = store.get("hotbars");
const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars : [];
store.set("hotbars", hotbars.map(({ id, ...rest }) => ({
id: id || uuid.v4(),
...rest,
})));
},
}),
injectionToken: hotbarStoreMigrationInjectionToken,
});
export default v500Alpha2HotbarStoreMigrationInjectable;

View File

@ -0,0 +1,173 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import * as uuid from "uuid";
import type { 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 "../../../migrations/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";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token";
import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable";
import loggerInjectable from "../../../common/logger.injectable";
interface Pre500WorkspaceStoreModel {
workspaces: {
id: string;
name: string;
}[];
}
interface PartialHotbar {
id: string;
name: string;
items: (null | HotbarItem)[];
}
const v500Beta10HotbarStoreMigrationInjectable = getInjectable({
id: "v5.0.0-beta.10-hotbar-store-migration",
instantiate: (di) => {
const userDataPath = di.inject(directoryForUserDataInjectable);
const joinPaths = di.inject(joinPathsInjectable);
const readJsonSync = di.inject(readJsonSyncInjectable);
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
const logger = di.inject(loggerInjectable);
return {
version: "5.0.0-beta.10",
run(store) {
const rawHotbars = store.get("hotbars");
const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars.filter(h => h && typeof h === "object") : [];
// Hotbars might be empty, if some of the previous migrations weren't run
if (hotbars.length === 0) {
const hotbar = getEmptyHotbar("default");
const { metadata: { uid, name, source }} = catalogCatalogEntity;
hotbar.items[0] = { entity: { uid, name, source }};
hotbars.push(hotbar);
}
try {
const workspaceStoreData: Pre500WorkspaceStoreModel = readJsonSync(joinPaths(userDataPath, "lens-workspace-store.json"));
const { clusters = [] }: ClusterStoreModel = readJsonSync(joinPaths(userDataPath, "lens-cluster-store.json"));
const workspaceHotbars = new Map<string, PartialHotbar>(); // mapping from WorkspaceId to HotBar
for (const { id, name } of workspaceStoreData.workspaces) {
logger.info(`Creating new hotbar for ${name}`);
workspaceHotbars.set(id, {
id: uuid.v4(), // don't use the old IDs as they aren't necessarily UUIDs
items: [],
name: `Workspace: ${name}`,
});
}
{
// grab the default named hotbar or the first.
const defaultHotbarIndex = Math.max(0, hotbars.findIndex(hotbar => hotbar.name === "default"));
const [{ name, id, items }] = hotbars.splice(defaultHotbarIndex, 1);
workspaceHotbars.set("default", {
name,
id,
items: items.filter(isDefined),
});
}
for (const cluster of clusters) {
const uid = generateNewIdFor(cluster);
for (const workspaceId of cluster.workspaces ?? [cluster.workspace].filter(isDefined)) {
const workspaceHotbar = workspaceHotbars.get(workspaceId);
if (!workspaceHotbar) {
logger.info(`Cluster ${uid} has unknown workspace ID, skipping`);
continue;
}
logger.info(`Adding cluster ${uid} to ${workspaceHotbar.name}`);
if (workspaceHotbar?.items.length < defaultHotbarCells) {
workspaceHotbar.items.push({
entity: {
uid: generateNewIdFor(cluster),
name: cluster.preferences?.clusterName || cluster.contextName,
},
});
}
}
}
for (const hotbar of workspaceHotbars.values()) {
if (hotbar.items.length === 0) {
logger.info(`Skipping ${hotbar.name} due to it being empty`);
continue;
}
while (hotbar.items.length < defaultHotbarCells) {
hotbar.items.push(null);
}
hotbars.push(hotbar as Hotbar);
}
/**
* Finally, make sure that the catalog entity hotbar item is in place.
* Just in case something else removed it.
*
* if every hotbar has elements that all not the `catalog-entity` item
*/
if (hotbars.every(hotbar => hotbar.items.every(item => item?.entity?.uid !== "catalog-entity"))) {
// note, we will add a new whole hotbar here called "default" if that was previously removed
const di = getLegacyGlobalDiForExtensionApi();
const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable);
const defaultHotbar = hotbars.find(hotbar => hotbar.name === "default");
const { metadata: { uid, name, source }} = catalogCatalogEntity;
if (defaultHotbar) {
const freeIndex = defaultHotbar.items.findIndex(i => i === null);
if (freeIndex === -1) {
// making a new hotbar is less destructive if the first hotbar
// called "default" is full than overriding a hotbar item
const hotbar = getEmptyHotbar("initial");
hotbar.items[0] = { entity: { uid, name, source }};
hotbars.unshift(hotbar);
} else {
defaultHotbar.items[freeIndex] = { entity: { uid, name, source }};
}
} else {
const hotbar = getEmptyHotbar("default");
hotbar.items[0] = { entity: { uid, name, source }};
hotbars.unshift(hotbar);
}
}
} catch (error) {
// ignore files being missing
if (isErrnoException(error) && error.code !== "ENOENT") {
throw error;
}
}
store.set("hotbars", hotbars);
},
};
},
injectionToken: hotbarStoreMigrationInjectionToken,
});
export default v500Beta10HotbarStoreMigrationInjectable;

View 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 { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token";
const v500Beta5HotbarStoreMigrationInjectable = getInjectable({
id: "v500-beta5-hotbar-store-migration",
instantiate: (di) => {
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
return {
version: "5.0.0-beta.5",
run(store) {
const rawHotbars = store.get("hotbars");
const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars : [];
for (const hotbar of hotbars) {
for (let i = 0; i < hotbar.items.length; i += 1) {
const item = hotbar.items[i];
if (!item) {
continue;
}
const entity = catalogEntityRegistry.findById(item.entity.uid);
if (!entity) {
// Clear disabled item
hotbar.items[i] = null;
} else {
// Save additional data
item.entity = {
...item.entity,
name: entity.metadata.name,
source: entity.metadata.source,
};
}
}
}
store.set("hotbars", hotbars);
},
};
},
injectionToken: hotbarStoreMigrationInjectionToken,
});
export default v500Beta5HotbarStoreMigrationInjectable;

View File

@ -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;

View File

@ -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;

View File

@ -1,166 +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 * 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";
import joinPathsInjectable from "../../common/path/join-paths.injectable";
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);
const joinPaths = di.inject(joinPathsInjectable);
// 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(joinPaths(userDataPath, "lens-workspace-store.json"));
const { clusters = [] }: ClusterStoreModel = fse.readJSONSync(joinPaths(userDataPath, "lens-cluster-store.json"));
const workspaceHotbars = new Map<string, PartialHotbar>(); // mapping from WorkspaceId to HotBar
for (const { id, name } of workspaceStoreData.workspaces) {
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;

View File

@ -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;

View File

@ -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,
);