mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove async store load, fix hotbar migrations
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
a630b595c3
commit
c253637594
@ -37,27 +37,27 @@ interface DoneCallback {
|
||||
* This is necessary because Jest doesn't do this correctly.
|
||||
* @param fn The function to call
|
||||
*/
|
||||
export function wrapJestLifecycle(fn: () => Promise<void>): (done: DoneCallback) => void {
|
||||
export function wrapJestLifecycle(fn: () => Promise<void> | void): (done: DoneCallback) => void {
|
||||
return function (done: DoneCallback) {
|
||||
fn()
|
||||
(async () => fn())()
|
||||
.then(() => done())
|
||||
.catch(error => done.fail(error));
|
||||
};
|
||||
}
|
||||
|
||||
export function beforeAllWrapped(fn: () => Promise<void>): void {
|
||||
export function beforeAllWrapped(fn: () => Promise<void> | void): void {
|
||||
beforeAll(wrapJestLifecycle(fn));
|
||||
}
|
||||
|
||||
export function beforeEachWrapped(fn: () => Promise<void>): void {
|
||||
export function beforeEachWrapped(fn: () => Promise<void> | void): void {
|
||||
beforeEach(wrapJestLifecycle(fn));
|
||||
}
|
||||
|
||||
export function afterAllWrapped(fn: () => Promise<void>): void {
|
||||
export function afterAllWrapped(fn: () => Promise<void> | void): void {
|
||||
afterAll(wrapJestLifecycle(fn));
|
||||
}
|
||||
|
||||
export function afterEachWrapped(fn: () => Promise<void>): void {
|
||||
export function afterEachWrapped(fn: () => Promise<void> | void): void {
|
||||
afterEach(wrapJestLifecycle(fn));
|
||||
}
|
||||
|
||||
|
||||
@ -95,7 +95,7 @@ describe("empty config", () => {
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
await ClusterStore.createInstance().load();
|
||||
ClusterStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -203,7 +203,7 @@ describe("config with existing clusters", () => {
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
return ClusterStore.createInstance().load();
|
||||
return ClusterStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -285,7 +285,7 @@ users:
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
return ClusterStore.createInstance().load();
|
||||
return ClusterStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -344,7 +344,7 @@ describe("pre 2.0 config with an existing cluster", () => {
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
return ClusterStore.createInstance().load();
|
||||
return ClusterStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -414,7 +414,7 @@ describe("pre 2.6.0 config with a cluster that has arrays in auth config", () =>
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
return ClusterStore.createInstance().load();
|
||||
return ClusterStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -456,7 +456,7 @@ describe("pre 2.6.0 config with a cluster icon", () => {
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
return ClusterStore.createInstance().load();
|
||||
return ClusterStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -495,7 +495,7 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => {
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
return ClusterStore.createInstance().load();
|
||||
return ClusterStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -531,7 +531,7 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => {
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
return ClusterStore.createInstance().load();
|
||||
return ClusterStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@ -20,10 +20,11 @@
|
||||
*/
|
||||
|
||||
import mockFs from "mock-fs";
|
||||
import { catalogEntity } from "../../main/catalog-sources/general";
|
||||
import { ClusterStore } from "../cluster-store";
|
||||
import { HotbarStore } from "../hotbar-store";
|
||||
|
||||
jest.mock("../../renderer/api/catalog-entity-registry", () => ({
|
||||
jest.mock("../../main/catalog/catalog-entity-registry", () => ({
|
||||
catalogEntityRegistry: {
|
||||
items: [
|
||||
{
|
||||
@ -39,7 +40,8 @@ jest.mock("../../renderer/api/catalog-entity-registry", () => ({
|
||||
name: "my_shiny_cluster",
|
||||
source: "remote"
|
||||
}
|
||||
}
|
||||
},
|
||||
catalogEntity,
|
||||
]
|
||||
}
|
||||
}));
|
||||
@ -120,29 +122,31 @@ jest.mock("electron", () => {
|
||||
|
||||
describe("HotbarStore", () => {
|
||||
beforeEach(() => {
|
||||
ClusterStore.resetInstance();
|
||||
mockFs({
|
||||
"tmp": {
|
||||
"lens-hotbar-store.json": JSON.stringify({})
|
||||
}
|
||||
});
|
||||
ClusterStore.createInstance();
|
||||
|
||||
HotbarStore.resetInstance();
|
||||
mockFs({ tmp: { "lens-hotbar-store.json": "{}" } });
|
||||
HotbarStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ClusterStore.resetInstance();
|
||||
HotbarStore.resetInstance();
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
describe("load", () => {
|
||||
it("loads one hotbar by default", () => {
|
||||
HotbarStore.createInstance().load();
|
||||
expect(HotbarStore.getInstance().hotbars.length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("add", () => {
|
||||
it("adds a hotbar", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.add({ name: "hottest" });
|
||||
expect(hotbarStore.hotbars.length).toEqual(2);
|
||||
});
|
||||
@ -150,23 +154,20 @@ describe("HotbarStore", () => {
|
||||
|
||||
describe("hotbar items", () => {
|
||||
it("initially creates 12 empty cells", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
expect(hotbarStore.getActive().items.length).toEqual(12);
|
||||
});
|
||||
|
||||
it("initially adds catalog entity as first item", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
expect(hotbarStore.getActive().items[0].entity.name).toEqual("Catalog");
|
||||
});
|
||||
|
||||
it("adds items", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
const items = hotbarStore.getActive().items.filter(Boolean);
|
||||
|
||||
@ -174,9 +175,8 @@ describe("HotbarStore", () => {
|
||||
});
|
||||
|
||||
it("removes items", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
hotbarStore.removeFromHotbar("test");
|
||||
hotbarStore.removeFromHotbar("catalog-entity");
|
||||
@ -186,9 +186,8 @@ describe("HotbarStore", () => {
|
||||
});
|
||||
|
||||
it("does nothing if removing with invalid uid", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
hotbarStore.removeFromHotbar("invalid uid");
|
||||
const items = hotbarStore.getActive().items.filter(Boolean);
|
||||
@ -197,9 +196,8 @@ describe("HotbarStore", () => {
|
||||
});
|
||||
|
||||
it("moves item to empty cell", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
hotbarStore.addToHotbar(minikubeCluster);
|
||||
hotbarStore.addToHotbar(awsCluster);
|
||||
@ -213,9 +211,8 @@ describe("HotbarStore", () => {
|
||||
});
|
||||
|
||||
it("moves items down", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
hotbarStore.addToHotbar(minikubeCluster);
|
||||
hotbarStore.addToHotbar(awsCluster);
|
||||
@ -229,9 +226,8 @@ describe("HotbarStore", () => {
|
||||
});
|
||||
|
||||
it("moves items up", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
hotbarStore.addToHotbar(minikubeCluster);
|
||||
hotbarStore.addToHotbar(awsCluster);
|
||||
@ -245,9 +241,8 @@ describe("HotbarStore", () => {
|
||||
});
|
||||
|
||||
it("does nothing when item moved to same cell", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
hotbarStore.restackItems(1, 1);
|
||||
|
||||
@ -255,9 +250,8 @@ describe("HotbarStore", () => {
|
||||
});
|
||||
|
||||
it("new items takes first empty cell", () => {
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
hotbarStore.addToHotbar(awsCluster);
|
||||
hotbarStore.restackItems(0, 3);
|
||||
@ -268,13 +262,13 @@ describe("HotbarStore", () => {
|
||||
|
||||
it("throws if invalid arguments provided", () => {
|
||||
// Prevent writing to stderr during this render.
|
||||
const err = console.error;
|
||||
const { error, warn } = console;
|
||||
|
||||
console.error = jest.fn();
|
||||
console.warn = jest.fn();
|
||||
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const hotbarStore = HotbarStore.getInstance();
|
||||
|
||||
hotbarStore.load();
|
||||
hotbarStore.addToHotbar(testCluster);
|
||||
|
||||
expect(() => hotbarStore.restackItems(-5, 0)).toThrow();
|
||||
@ -283,7 +277,8 @@ describe("HotbarStore", () => {
|
||||
expect(() => hotbarStore.restackItems(11, 112)).toThrow();
|
||||
|
||||
// Restore writing to stderr.
|
||||
console.error = err;
|
||||
console.error = error;
|
||||
console.warn = warn;
|
||||
});
|
||||
});
|
||||
|
||||
@ -354,7 +349,7 @@ describe("HotbarStore", () => {
|
||||
|
||||
mockFs(mockOpts);
|
||||
|
||||
return HotbarStore.createInstance().load();
|
||||
HotbarStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@ -52,7 +52,7 @@ describe("user store tests", () => {
|
||||
|
||||
(UserStore.createInstance() as any).refreshNewContexts = jest.fn(() => Promise.resolve());
|
||||
|
||||
return UserStore.getInstance().load();
|
||||
UserStore.getInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -111,7 +111,7 @@ describe("user store tests", () => {
|
||||
}
|
||||
});
|
||||
|
||||
return UserStore.createInstance().load();
|
||||
UserStore.createInstance();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@ -29,16 +29,14 @@ import logger from "../main/logger";
|
||||
import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc";
|
||||
import isEqual from "lodash/isEqual";
|
||||
|
||||
export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
||||
autoLoad?: boolean;
|
||||
syncEnabled?: boolean;
|
||||
export interface BaseStoreParams<T> extends ConfOptions<T> {
|
||||
syncOptions?: IReactionOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: T should only contain base JSON serializable types.
|
||||
*/
|
||||
export abstract class BaseStore<T = any> extends Singleton {
|
||||
export abstract class BaseStore<T> extends Singleton {
|
||||
protected storeConfig?: Config<T>;
|
||||
protected syncDisposers: Disposer[] = [];
|
||||
|
||||
@ -48,16 +46,27 @@ export abstract class BaseStore<T = any> extends Singleton {
|
||||
return when(() => this.isLoaded);
|
||||
}
|
||||
|
||||
protected constructor(protected params: BaseStoreParams) {
|
||||
protected constructor(protected params: BaseStoreParams<T>) {
|
||||
super();
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
this.params = {
|
||||
autoLoad: false,
|
||||
syncEnabled: true,
|
||||
...params,
|
||||
};
|
||||
this.init();
|
||||
/**
|
||||
* This must be called after the last child's constructor is finished (or just before it finishes)
|
||||
*/
|
||||
load() {
|
||||
this.storeConfig = new Config({
|
||||
...this.params,
|
||||
projectName: "lens",
|
||||
projectVersion: getAppVersion(),
|
||||
cwd: this.cwd(),
|
||||
});
|
||||
|
||||
logger.info(`[STORE]: LOADED from ${this.path}`);
|
||||
this.fromStore(this.storeConfig.store);
|
||||
this.isLoaded = true;
|
||||
|
||||
this.enableSync();
|
||||
}
|
||||
|
||||
get name() {
|
||||
@ -76,31 +85,6 @@ export abstract class BaseStore<T = any> extends Singleton {
|
||||
return this.storeConfig?.path || "";
|
||||
}
|
||||
|
||||
protected async init() {
|
||||
if (this.params.autoLoad) {
|
||||
await this.load();
|
||||
}
|
||||
|
||||
if (this.params.syncEnabled) {
|
||||
await this.whenLoaded;
|
||||
this.enableSync();
|
||||
}
|
||||
}
|
||||
|
||||
async load() {
|
||||
const { autoLoad, syncEnabled, ...confOptions } = this.params;
|
||||
|
||||
this.storeConfig = new Config({
|
||||
...confOptions,
|
||||
projectName: "lens",
|
||||
projectVersion: getAppVersion(),
|
||||
cwd: this.cwd(),
|
||||
});
|
||||
logger.info(`[STORE]: LOADED from ${this.path}`);
|
||||
this.fromStore(this.storeConfig.store);
|
||||
this.isLoaded = true;
|
||||
}
|
||||
|
||||
protected cwd() {
|
||||
return (app || remote.app).getPath("userData");
|
||||
}
|
||||
@ -159,10 +143,7 @@ export abstract class BaseStore<T = any> extends Singleton {
|
||||
protected applyWithoutSync(callback: () => void) {
|
||||
this.disableSync();
|
||||
runInAction(callback);
|
||||
|
||||
if (this.params.syncEnabled) {
|
||||
this.enableSync();
|
||||
}
|
||||
this.enableSync();
|
||||
}
|
||||
|
||||
protected onSync(model: T) {
|
||||
|
||||
@ -110,6 +110,8 @@ export interface ClusterPrometheusPreferences {
|
||||
};
|
||||
}
|
||||
|
||||
const initialStates = "cluster:states";
|
||||
|
||||
export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
private static StateChannel = "cluster:state";
|
||||
|
||||
@ -121,8 +123,8 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
return path.resolve(ClusterStore.storedKubeConfigFolder, clusterId);
|
||||
}
|
||||
|
||||
@observable clusters = observable.map<ClusterId, Cluster>();
|
||||
@observable removedClusters = observable.map<ClusterId, Cluster>();
|
||||
clusters = observable.map<ClusterId, Cluster>();
|
||||
removedClusters = observable.map<ClusterId, Cluster>();
|
||||
|
||||
protected disposer = disposer();
|
||||
|
||||
@ -137,31 +139,27 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
||||
});
|
||||
|
||||
makeObservable(this);
|
||||
|
||||
this.load();
|
||||
this.pushStateToViewsAutomatically();
|
||||
}
|
||||
|
||||
async load() {
|
||||
const initialStates = "cluster:states";
|
||||
async loadInitialOnRenderer() {
|
||||
logger.info("[CLUSTER-STORE] requesting initial state sync");
|
||||
|
||||
await super.load();
|
||||
|
||||
if (ipcRenderer) {
|
||||
logger.info("[CLUSTER-STORE] requesting initial state sync");
|
||||
|
||||
for (const { id, state } of await requestMain(initialStates)) {
|
||||
this.getById(id)?.setState(state);
|
||||
}
|
||||
} else if (ipcMain) {
|
||||
ipcMainHandle(initialStates, () => {
|
||||
return this.clustersList.map(cluster => ({
|
||||
id: cluster.id,
|
||||
state: cluster.getState(),
|
||||
}));
|
||||
});
|
||||
for (const { id, state } of await requestMain(initialStates)) {
|
||||
this.getById(id)?.setState(state);
|
||||
}
|
||||
}
|
||||
|
||||
provideInitialFromMain() {
|
||||
ipcMainHandle(initialStates, () => {
|
||||
return this.clustersList.map(cluster => ({
|
||||
id: cluster.id,
|
||||
state: cluster.getState(),
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
protected pushStateToViewsAutomatically() {
|
||||
if (ipcMain) {
|
||||
this.disposer.push(
|
||||
|
||||
@ -26,7 +26,6 @@ import * as uuid from "uuid";
|
||||
import isNull from "lodash/isNull";
|
||||
import { toJS } from "./utils";
|
||||
import { CatalogEntity } from "./catalog";
|
||||
import { catalogEntity } from "../main/catalog-sources/general";
|
||||
|
||||
export interface HotbarItem {
|
||||
entity: {
|
||||
@ -72,6 +71,7 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
migrations,
|
||||
});
|
||||
makeObservable(this);
|
||||
this.load();
|
||||
}
|
||||
|
||||
get activeHotbarId() {
|
||||
@ -92,30 +92,13 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
return this.hotbarIndex(this.activeHotbarId);
|
||||
}
|
||||
|
||||
get defaultHotbarInitialItems() {
|
||||
const { metadata: { uid, name, source } } = catalogEntity;
|
||||
const initialItem = { entity: { uid, name, source }};
|
||||
|
||||
return [
|
||||
initialItem,
|
||||
...Array.from(Array(defaultHotbarCells - 1).fill(null))
|
||||
];
|
||||
}
|
||||
|
||||
get initialItems() {
|
||||
static getInitialItems() {
|
||||
return [...Array.from(Array(defaultHotbarCells).fill(null))];
|
||||
}
|
||||
|
||||
@action protected async fromStore(data: Partial<HotbarStoreModel> = {}) {
|
||||
if (data.hotbars?.length === 0) {
|
||||
this.hotbars = [{
|
||||
id: uuid.v4(),
|
||||
name: "Default",
|
||||
items: this.defaultHotbarInitialItems,
|
||||
}];
|
||||
} else {
|
||||
this.hotbars = data.hotbars;
|
||||
}
|
||||
@action
|
||||
protected async fromStore(data: Partial<HotbarStoreModel> = {}) {
|
||||
this.hotbars = data.hotbars;
|
||||
|
||||
if (data.activeHotbarId) {
|
||||
if (this.getById(data.activeHotbarId)) {
|
||||
@ -143,7 +126,7 @@ export class HotbarStore extends BaseStore<HotbarStoreModel> {
|
||||
add(data: HotbarCreateOptions) {
|
||||
const {
|
||||
id = uuid.v4(),
|
||||
items = this.initialItems,
|
||||
items = HotbarStore.getInitialItems(),
|
||||
name,
|
||||
} = data;
|
||||
|
||||
|
||||
@ -68,7 +68,28 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
||||
configName: "lens-user-store",
|
||||
migrations,
|
||||
});
|
||||
|
||||
makeObservable(this);
|
||||
fileNameMigration();
|
||||
this.load();
|
||||
|
||||
if (app) {
|
||||
// track telemetry availability
|
||||
reaction(() => this.allowTelemetry, allowed => {
|
||||
appEventBus.emit({ name: "telemetry", action: allowed ? "enabled" : "disabled" });
|
||||
});
|
||||
|
||||
// open at system start-up
|
||||
reaction(() => this.openAtLogin, openAtLogin => {
|
||||
app.setLoginItemSettings({
|
||||
openAtLogin,
|
||||
openAsHidden: true,
|
||||
args: ["--hidden"]
|
||||
});
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@observable lastSeenAppVersion = "0.0.0";
|
||||
@ -101,33 +122,6 @@ export class UserStore extends BaseStore<UserStoreModel> {
|
||||
[path.join(os.homedir(), ".kube"), {}]
|
||||
]);
|
||||
|
||||
async load(): Promise<void> {
|
||||
/**
|
||||
* This has to be here before the call to `new Config` in `super.load()`
|
||||
* as we have to make sure that file is in the expected place for that call
|
||||
*/
|
||||
await fileNameMigration();
|
||||
await super.load();
|
||||
|
||||
if (app) {
|
||||
// track telemetry availability
|
||||
reaction(() => this.allowTelemetry, allowed => {
|
||||
appEventBus.emit({ name: "telemetry", action: allowed ? "enabled" : "disabled" });
|
||||
});
|
||||
|
||||
// open at system start-up
|
||||
reaction(() => this.openAtLogin, openAtLogin => {
|
||||
app.setLoginItemSettings({
|
||||
openAtLogin,
|
||||
openAsHidden: true,
|
||||
args: ["--hidden"]
|
||||
});
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@computed get isNewVersion() {
|
||||
return semver.gt(getAppVersion(), this.lastSeenAppVersion);
|
||||
}
|
||||
|
||||
@ -55,6 +55,7 @@ export class WeblinkStore extends BaseStore<WeblinkStoreModel> {
|
||||
migrations,
|
||||
});
|
||||
makeObservable(this);
|
||||
this.load();
|
||||
}
|
||||
|
||||
@action protected async fromStore(data: Partial<WeblinkStoreModel> = {}) {
|
||||
|
||||
@ -26,13 +26,13 @@ import type { LensExtension } from "./lens-extension";
|
||||
export abstract class ExtensionStore<T> extends BaseStore<T> {
|
||||
protected extension: LensExtension;
|
||||
|
||||
async loadExtension(extension: LensExtension) {
|
||||
loadExtension(extension: LensExtension) {
|
||||
this.extension = extension;
|
||||
|
||||
return super.load();
|
||||
}
|
||||
|
||||
async load() {
|
||||
load() {
|
||||
if (!this.extension) { return; }
|
||||
|
||||
return super.load();
|
||||
|
||||
@ -39,6 +39,7 @@ export class ExtensionsStore extends BaseStore<LensExtensionsStoreModel> {
|
||||
configName: "lens-extensions",
|
||||
});
|
||||
makeObservable(this);
|
||||
this.load();
|
||||
}
|
||||
|
||||
@computed
|
||||
|
||||
@ -67,6 +67,6 @@ const generalEntities = observable([
|
||||
preferencesEntity
|
||||
]);
|
||||
|
||||
export function initializeGeneralEntities() {
|
||||
export function syncGeneralEntities() {
|
||||
catalogEntityRegistry.addObservableSource("lens:general", generalEntities);
|
||||
}
|
||||
|
||||
@ -19,6 +19,6 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export { initializeWeblinks } from "./weblinks";
|
||||
export { syncWeblinks } from "./weblinks";
|
||||
export { KubeconfigSyncManager } from "./kubeconfig-sync";
|
||||
export { initializeGeneralEntities } from "./general";
|
||||
export { syncGeneralEntities } from "./general";
|
||||
|
||||
@ -69,7 +69,7 @@ async function validateLink(link: WebLink) {
|
||||
}
|
||||
|
||||
|
||||
export function initializeWeblinks() {
|
||||
export function syncWeblinks() {
|
||||
const weblinkStore = WeblinkStore.getInstance();
|
||||
const weblinks = observable.array(defaultLinks);
|
||||
|
||||
|
||||
@ -42,6 +42,7 @@ export class FilesystemProvisionerStore extends BaseStore<FSProvisionModel> {
|
||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||
});
|
||||
makeObservable(this);
|
||||
this.load();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -48,11 +48,17 @@ import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
|
||||
import { pushCatalogToRenderer } from "./catalog-pusher";
|
||||
import { catalogEntityRegistry } from "./catalog";
|
||||
import { HelmRepoManager } from "./helm/helm-repo-manager";
|
||||
import { KubeconfigSyncManager } from "./catalog-sources";
|
||||
import { syncGeneralEntities, syncWeblinks, KubeconfigSyncManager } from "./catalog-sources";
|
||||
import { handleWsUpgrade } from "./proxy/ws-upgrade";
|
||||
import configurePackages from "../common/configure-packages";
|
||||
import { PrometheusProviderRegistry } from "./prometheus";
|
||||
import * as initializers from "./initializers";
|
||||
import { ClusterStore } from "../common/cluster-store";
|
||||
import { HotbarStore } from "../common/hotbar-store";
|
||||
import { UserStore } from "../common/user-store";
|
||||
import { WeblinkStore } from "../common/weblink-store";
|
||||
import { ExtensionsStore } from "../extensions/extensions-store";
|
||||
import { FilesystemProvisionerStore } from "./extension-filesystem";
|
||||
|
||||
const workingDir = path.join(app.getPath("appData"), appName);
|
||||
const cleanup = disposer();
|
||||
@ -122,9 +128,18 @@ app.on("ready", async () => {
|
||||
|
||||
PrometheusProviderRegistry.createInstance();
|
||||
initializers.initPrometheusProviderRegistry();
|
||||
syncGeneralEntities();
|
||||
|
||||
await initializers.initializeStores();
|
||||
initializers.initializeWeblinks();
|
||||
logger.info("💾 Loading stores");
|
||||
|
||||
UserStore.createInstance();
|
||||
ClusterStore.createInstance().provideInitialFromMain();
|
||||
HotbarStore.createInstance();
|
||||
ExtensionsStore.createInstance();
|
||||
FilesystemProvisionerStore.createInstance();
|
||||
WeblinkStore.createInstance();
|
||||
|
||||
syncWeblinks();
|
||||
|
||||
HelmRepoManager.createInstance(); // create the instance
|
||||
|
||||
@ -182,7 +197,6 @@ app.on("ready", async () => {
|
||||
ipcMainOn(IpcRendererNavigationEvents.LOADED, () => {
|
||||
cleanup.push(pushCatalogToRenderer(catalogEntityRegistry));
|
||||
KubeconfigSyncManager.getInstance().startSync();
|
||||
initializers.initializeGeneralEntities();
|
||||
startUpdateChecking();
|
||||
LensProtocolRouterMain.getInstance().rendererLoaded = true;
|
||||
});
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export { initializeGeneralEntities } from "../catalog-sources";
|
||||
@ -22,6 +22,3 @@
|
||||
export * from "./registries";
|
||||
export * from "./metrics-providers";
|
||||
export * from "./ipc";
|
||||
export * from "./weblinks";
|
||||
export * from "./stores";
|
||||
export * from "./general-entities";
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { HotbarStore } from "../../common/hotbar-store";
|
||||
import { ClusterStore } from "../../common/cluster-store";
|
||||
import { UserStore } from "../../common/user-store";
|
||||
import { ExtensionsStore } from "../../extensions/extensions-store";
|
||||
import { FilesystemProvisionerStore } from "../extension-filesystem";
|
||||
import { WeblinkStore } from "../../common/weblink-store";
|
||||
import logger from "../logger";
|
||||
|
||||
export async function initializeStores() {
|
||||
const userStore = UserStore.createInstance();
|
||||
const clusterStore = ClusterStore.createInstance();
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const extensionsStore = ExtensionsStore.createInstance();
|
||||
const filesystemStore = FilesystemProvisionerStore.createInstance();
|
||||
const weblinkStore = WeblinkStore.createInstance();
|
||||
|
||||
logger.info("💾 Loading stores");
|
||||
// preload
|
||||
await Promise.all([
|
||||
userStore.load(),
|
||||
clusterStore.load(),
|
||||
hotbarStore.load(),
|
||||
extensionsStore.load(),
|
||||
filesystemStore.load(),
|
||||
weblinkStore.load()
|
||||
]);
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export { initializeWeblinks } from "../catalog-sources";
|
||||
@ -20,9 +20,10 @@
|
||||
*/
|
||||
|
||||
// Cleans up a store that had the state related data stored
|
||||
import type { Hotbar } from "../../common/hotbar-store";
|
||||
import { Hotbar, HotbarStore } from "../../common/hotbar-store";
|
||||
import * as uuid from "uuid";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
import { catalogEntity } from "../../main/catalog-sources/general";
|
||||
|
||||
export default {
|
||||
version: "5.0.0-alpha.0",
|
||||
@ -30,9 +31,13 @@ export default {
|
||||
const hotbar: Hotbar = {
|
||||
id: uuid.v4(),
|
||||
name: "default",
|
||||
items: [...Array.from(Array(12).fill(null))],
|
||||
items: HotbarStore.getInitialItems(),
|
||||
};
|
||||
|
||||
const { metadata: { uid, name, source } } = catalogEntity;
|
||||
|
||||
hotbar.items[0] = { entity: { uid, name, source } };
|
||||
|
||||
store.set("hotbars", [hotbar]);
|
||||
}
|
||||
} as MigrationDeclaration;
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
import type { Hotbar } from "../../common/hotbar-store";
|
||||
import { catalogEntityRegistry } from "../../renderer/api/catalog-entity-registry";
|
||||
import { catalogEntityRegistry } from "../../main/catalog";
|
||||
import type { MigrationDeclaration } from "../helpers";
|
||||
|
||||
export default {
|
||||
|
||||
@ -23,18 +23,18 @@ import fse from "fs-extra";
|
||||
import { app, remote } from "electron";
|
||||
import path from "path";
|
||||
|
||||
export async function fileNameMigration() {
|
||||
export function fileNameMigration() {
|
||||
const userDataPath = (app || remote.app).getPath("userData");
|
||||
const configJsonPath = path.join(userDataPath, "config.json");
|
||||
const lensUserStoreJsonPath = path.join(userDataPath, "lens-user-store.json");
|
||||
|
||||
try {
|
||||
await fse.move(configJsonPath, lensUserStoreJsonPath);
|
||||
fse.moveSync(configJsonPath, lensUserStoreJsonPath);
|
||||
} catch (error) {
|
||||
if (error.code === "ENOENT" && error.path === configJsonPath) { // (No such file or directory)
|
||||
return; // file already moved
|
||||
} else if (error.message === "dest already exists.") {
|
||||
await fse.remove(configJsonPath);
|
||||
fse.removeSync(configJsonPath);
|
||||
} else {
|
||||
// pass other errors along
|
||||
throw error;
|
||||
|
||||
@ -42,6 +42,11 @@ import { ExtensionInstallationStateStore } from "./components/+extensions/extens
|
||||
import { DefaultProps } from "./mui-base-theme";
|
||||
import configurePackages from "../common/configure-packages";
|
||||
import * as initializers from "./initializers";
|
||||
import { HotbarStore } from "../common/hotbar-store";
|
||||
import { WeblinkStore } from "../common/weblink-store";
|
||||
import { ExtensionsStore } from "../extensions/extensions-store";
|
||||
import { FilesystemProvisionerStore } from "../main/extension-filesystem";
|
||||
import { ThemeStore } from "./theme.store";
|
||||
|
||||
configurePackages();
|
||||
|
||||
@ -79,7 +84,13 @@ export async function bootstrap(App: AppComponent) {
|
||||
ExtensionLoader.createInstance().init();
|
||||
ExtensionDiscovery.createInstance().init();
|
||||
|
||||
await initializers.initStores();
|
||||
UserStore.createInstance();
|
||||
await ClusterStore.createInstance().loadInitialOnRenderer();
|
||||
HotbarStore.createInstance();
|
||||
ExtensionsStore.createInstance();
|
||||
FilesystemProvisionerStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
WeblinkStore.createInstance();
|
||||
|
||||
ExtensionInstallationStateStore.bindIpcListeners();
|
||||
HelmRepoManager.createInstance(); // initialize the manager
|
||||
|
||||
@ -61,7 +61,7 @@ describe("Extensions", () => {
|
||||
ExtensionInstallationStateStore.reset();
|
||||
UserStore.resetInstance();
|
||||
|
||||
await UserStore.createInstance().load();
|
||||
UserStore.createInstance();
|
||||
|
||||
ExtensionDiscovery.resetInstance();
|
||||
ExtensionDiscovery.createInstance().uninstallExtension = jest.fn(() => Promise.resolve());
|
||||
|
||||
@ -27,5 +27,4 @@ export * from "./registries";
|
||||
export * from "./welcome-menu-registry";
|
||||
export * from "./workloads-overview-detail-registry";
|
||||
export * from "./catalog";
|
||||
export * from "./stores";
|
||||
export * from "./ipc";
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { HotbarStore } from "../../common/hotbar-store";
|
||||
import { ClusterStore } from "../../common/cluster-store";
|
||||
import { UserStore } from "../../common/user-store";
|
||||
import { ExtensionsStore } from "../../extensions/extensions-store";
|
||||
import { FilesystemProvisionerStore } from "../../main/extension-filesystem";
|
||||
|
||||
import { ThemeStore } from "../theme.store";
|
||||
import { WeblinkStore } from "../../common/weblink-store";
|
||||
|
||||
export async function initStores() {
|
||||
const userStore = UserStore.createInstance();
|
||||
const clusterStore = ClusterStore.createInstance();
|
||||
const extensionsStore = ExtensionsStore.createInstance();
|
||||
const filesystemStore = FilesystemProvisionerStore.createInstance();
|
||||
const themeStore = ThemeStore.createInstance();
|
||||
const hotbarStore = HotbarStore.createInstance();
|
||||
const weblinkStore = WeblinkStore.createInstance();
|
||||
|
||||
// preload common stores
|
||||
await Promise.all([
|
||||
userStore.load(),
|
||||
hotbarStore.load(),
|
||||
clusterStore.load(),
|
||||
extensionsStore.load(),
|
||||
filesystemStore.load(),
|
||||
themeStore.init(),
|
||||
weblinkStore.load()
|
||||
]);
|
||||
}
|
||||
@ -20,9 +20,11 @@
|
||||
*/
|
||||
|
||||
import { computed, observable, reaction, makeObservable } from "mobx";
|
||||
import { autoBind, boundMethod, Singleton } from "./utils";
|
||||
import { autoBind, iter, Singleton } from "./utils";
|
||||
import { UserStore } from "../common/user-store";
|
||||
import logger from "../main/logger";
|
||||
import darkThemeBase from "./themes/lens-dark.json";
|
||||
import lightThemeBase from "./themes/lens-light.json";
|
||||
|
||||
export type ThemeId = string;
|
||||
|
||||
@ -32,12 +34,25 @@ export enum ThemeType {
|
||||
}
|
||||
|
||||
export interface Theme {
|
||||
id: ThemeId; // filename without .json-extension
|
||||
type: ThemeType;
|
||||
name?: string;
|
||||
colors?: Record<string, string>;
|
||||
description?: string;
|
||||
author?: string;
|
||||
name: string;
|
||||
colors: Record<string, string>;
|
||||
description: string;
|
||||
author: string;
|
||||
}
|
||||
|
||||
const darkTheme: Theme = {
|
||||
...darkThemeBase,
|
||||
type: darkThemeBase.type as ThemeType,
|
||||
};
|
||||
|
||||
const lightTheme: Theme = {
|
||||
...lightThemeBase,
|
||||
type: lightThemeBase.type as ThemeType,
|
||||
};
|
||||
|
||||
export interface ThemeItems extends Theme {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class ThemeStore extends Singleton {
|
||||
@ -45,16 +60,12 @@ export class ThemeStore extends Singleton {
|
||||
|
||||
// bundled themes from `themes/${themeId}.json`
|
||||
private allThemes = observable.map<string, Theme>([
|
||||
["lens-dark", { id: "lens-dark", type: ThemeType.DARK }],
|
||||
["lens-light", { id: "lens-light", type: ThemeType.LIGHT }],
|
||||
["lens-dark", darkTheme],
|
||||
["lens-light", lightTheme],
|
||||
]);
|
||||
|
||||
@computed get themeIds(): string[] {
|
||||
return Array.from(this.allThemes.keys());
|
||||
}
|
||||
|
||||
@computed get themes(): Theme[] {
|
||||
return Array.from(this.allThemes.values());
|
||||
@computed get themes(): ThemeItems[] {
|
||||
return Array.from(iter.map(this.allThemes, ([id, theme]) => ({ id, ...theme })));
|
||||
}
|
||||
|
||||
@computed get activeThemeId(): string {
|
||||
@ -62,12 +73,7 @@ export class ThemeStore extends Singleton {
|
||||
}
|
||||
|
||||
@computed get activeTheme(): Theme {
|
||||
const activeTheme = this.allThemes.get(this.activeThemeId) ?? this.allThemes.get("lens-dark");
|
||||
|
||||
return {
|
||||
colors: {},
|
||||
...activeTheme,
|
||||
};
|
||||
return this.allThemes.get(this.activeThemeId) ?? this.allThemes.get("lens-dark");
|
||||
}
|
||||
|
||||
constructor() {
|
||||
@ -79,7 +85,7 @@ export class ThemeStore extends Singleton {
|
||||
// auto-apply active theme
|
||||
reaction(() => this.activeThemeId, async themeId => {
|
||||
try {
|
||||
this.applyTheme(await this.loadTheme(themeId));
|
||||
this.applyTheme(this.getThemeById(themeId));
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
UserStore.getInstance().resetTheme();
|
||||
@ -89,38 +95,10 @@ export class ThemeStore extends Singleton {
|
||||
});
|
||||
}
|
||||
|
||||
async init() {
|
||||
// preload all themes
|
||||
await Promise.all(this.themeIds.map(this.loadTheme));
|
||||
}
|
||||
|
||||
getThemeById(themeId: ThemeId): Theme {
|
||||
return this.allThemes.get(themeId);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
protected async loadTheme(themeId: ThemeId): Promise<Theme> {
|
||||
try {
|
||||
const existingTheme = this.getThemeById(themeId);
|
||||
|
||||
if (existingTheme) {
|
||||
const theme = await import(
|
||||
/* webpackChunkName: "themes/[name]" */
|
||||
`./themes/${themeId}.json`
|
||||
);
|
||||
|
||||
existingTheme.author = theme.author;
|
||||
existingTheme.colors = theme.colors;
|
||||
existingTheme.description = theme.description;
|
||||
existingTheme.name = theme.name;
|
||||
}
|
||||
|
||||
return existingTheme;
|
||||
} catch (err) {
|
||||
throw new Error(`Can't load theme "${themeId}": ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
protected applyTheme(theme: Theme) {
|
||||
if (!this.styles) {
|
||||
this.styles = document.createElement("style");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user