From 4055732d414c88e506e50191a33127ec50ab2230 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 17 Mar 2023 14:17:41 -0400 Subject: [PATCH] Fully split apart the user preferences storage Signed-off-by: Sebastian Malton --- .../src/common/__tests__/user-store.test.ts | 42 ++--- .../initialize-sentry-reporting.injectable.ts | 6 +- .../common/fetch/proxy-fetch.injectable.ts | 4 +- packages/core/src/common/fs/fs.injectable.ts | 2 + .../os/home-directory-path.injectable.ts | 2 +- ...igration.global-override-for-injectable.ts | 9 - packages/core/src/common/user-store/index.ts | 7 - .../src/common/user-store/migrations-token.ts | 11 -- .../user-store/user-store.injectable.ts | 30 ---- .../core/src/common/user-store/user-store.ts | 157 ------------------ ...timezone.global-override-for-injectable.ts | 0 .../current-timezone.injectable.ts | 0 ...ser-info.global-override-for-injectable.ts | 0 .../user-info.injectable.ts | 0 .../core/src/extensions/common-api/app.ts | 4 +- .../cluster/storage/main/init.injectable.ts | 4 +- .../storage/renderer/init.injectable.ts | 2 +- .../extension-install-registry.tsx | 38 ++--- .../application/start-up/start-up.tsx | 26 ++- .../application/theme/theme.tsx | 16 +- .../application/timezone/timezone.tsx | 18 +- .../editor-font-family/editor-font-family.tsx | 22 +-- .../editor-font-size/editor-font-size.tsx | 22 +-- .../editor/line-numbers/line-numbers.tsx | 25 ++- .../editor/minimap/minimap.tsx | 22 +-- .../editor/tab-size/tab-size.tsx | 22 +-- .../kubeconfig-sync/kubeconfig-sync.tsx | 12 +- .../kubectl-binary-download.tsx | 27 ++- .../kubectl-directory-for-binaries.tsx | 30 ++-- .../kubectl-download-mirror.tsx | 30 ++-- .../kubectl-path-to-binary.tsx | 68 ++++---- .../allow-untrusted-certificates.tsx | 28 ++-- .../proxy/http-proxy-url/http-proxy-url.tsx | 60 ++++--- .../automatic-error-reporting.tsx | 26 ++- .../copy-paste-from-terminal.tsx | 49 +++--- .../terminal-font-options.injectable.tsx | 12 +- .../terminal-font-size/terminal-font-size.tsx | 52 +++--- .../terminal-shell-path.tsx | 53 +++--- .../terminal-theme/terminal-theme.tsx | 17 +- .../shell-sync/main/setup-shell.injectable.ts | 2 +- .../renderer/initialize.injectable.ts | 2 +- .../common}/https-proxy.injectable.ts | 4 +- .../is-table-column-hidden.injectable.ts | 38 +++++ .../common}/kubeconfig-syncs.injectable.ts | 4 +- .../common}/lens-color-theme.injectable.ts | 8 +- .../common/migrations-token.ts | 11 ++ .../preference-descriptors.injectable.ts | 16 +- .../common}/preferences-helpers.ts | 4 +- .../common/reset-theme.injectable.ts | 24 +++ .../common}/shell-setting.injectable.ts | 8 +- .../common/state.injectable.ts | 19 +++ .../common/storage.injectable.ts | 88 ++++++++++ .../common}/terminal-config.injectable.ts | 9 +- .../terminal-copy-on-select.injectable.ts | 6 +- .../common}/terminal-theme.injectable.ts | 8 +- ...ggle-table-column-visibility.injectable.ts | 23 +++ .../main}/5.0.0-alpha.3.injectable.ts | 10 +- .../main}/5.0.3-beta.1.injectable.ts | 12 +- .../main}/file-name-migration.injectable.ts | 18 +- .../main/load-storage.injectable.ts | 26 +++ .../sync-open-at-login-with-os.injectable.ts | 8 +- .../renderer/load-storage.injectable.ts | 23 +++ .../__test__/kubeconfig-sync.test.ts | 4 +- .../kubeconfig-sync/manager.injectable.ts | 2 +- .../kubeconfig-sync/manager.ts | 2 +- .../helm/exec-helm/exec-env.injectable.ts | 2 +- .../main/kubectl/create-kubectl.injectable.ts | 4 +- packages/core/src/main/kubectl/kubectl.ts | 18 +- .../local-shell-session.ts | 8 +- .../local-shell-session/open.injectable.ts | 6 +- .../node-shell-session/open.injectable.ts | 2 +- .../main/stores/init-user-store.injectable.ts | 26 --- .../get-base-registry-url.injectable.tsx | 6 +- .../renderer/components/dock/logs/list.tsx | 10 +- .../terminal/create-terminal.injectable.ts | 5 +- .../components/dock/terminal/terminal.ts | 2 +- .../components/item-object-list/content.tsx | 16 +- .../components/locale-date/locale-date.tsx | 12 +- .../monaco-editor/monaco-editor.tsx | 33 ++-- .../add-sync-entries.injectable.tsx | 6 +- .../stores/init-user-store.injectable.ts | 23 --- .../src/renderer/themes/active.injectable.ts | 2 +- .../themes/apply-lens-theme.injectable.ts | 6 +- .../setup-apply-active-theme.injectable.ts | 2 +- .../themes/terminal-colors.injectable.ts | 2 +- .../src/test-utils/override-fs-with-fakes.ts | 1 + 86 files changed, 720 insertions(+), 806 deletions(-) delete mode 100644 packages/core/src/common/user-store/file-name-migration.global-override-for-injectable.ts delete mode 100644 packages/core/src/common/user-store/index.ts delete mode 100644 packages/core/src/common/user-store/migrations-token.ts delete mode 100644 packages/core/src/common/user-store/user-store.injectable.ts delete mode 100644 packages/core/src/common/user-store/user-store.ts rename packages/core/src/common/{user-store => vars}/current-timezone.global-override-for-injectable.ts (100%) rename packages/core/src/common/{user-store => vars}/current-timezone.injectable.ts (100%) rename packages/core/src/common/{user-store => vars}/user-info.global-override-for-injectable.ts (100%) rename packages/core/src/common/{user-store => vars}/user-info.injectable.ts (100%) rename packages/core/src/{common/user-store => features/user-preferences/common}/https-proxy.injectable.ts (78%) create mode 100644 packages/core/src/features/user-preferences/common/is-table-column-hidden.injectable.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/kubeconfig-syncs.injectable.ts (68%) rename packages/core/src/{common/user-store => features/user-preferences/common}/lens-color-theme.injectable.ts (78%) create mode 100644 packages/core/src/features/user-preferences/common/migrations-token.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/preference-descriptors.injectable.ts (89%) rename packages/core/src/{common/user-store => features/user-preferences/common}/preferences-helpers.ts (94%) create mode 100644 packages/core/src/features/user-preferences/common/reset-theme.injectable.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/shell-setting.injectable.ts (63%) create mode 100644 packages/core/src/features/user-preferences/common/state.injectable.ts create mode 100644 packages/core/src/features/user-preferences/common/storage.injectable.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/terminal-config.injectable.ts (60%) rename packages/core/src/{common/user-store => features/user-preferences/common}/terminal-copy-on-select.injectable.ts (69%) rename packages/core/src/{common/user-store => features/user-preferences/common}/terminal-theme.injectable.ts (79%) create mode 100644 packages/core/src/features/user-preferences/common/toggle-table-column-visibility.injectable.ts rename packages/core/src/{main/user-store/migrations => features/user-preferences/main}/5.0.0-alpha.3.injectable.ts (70%) rename packages/core/src/{main/user-store/migrations => features/user-preferences/main}/5.0.3-beta.1.injectable.ts (89%) rename packages/core/src/{common/user-store => features/user-preferences/main}/file-name-migration.injectable.ts (64%) create mode 100644 packages/core/src/features/user-preferences/main/load-storage.injectable.ts rename packages/core/src/{main/user-store => features/user-preferences/main}/sync-open-at-login-with-os.injectable.ts (72%) create mode 100644 packages/core/src/features/user-preferences/renderer/load-storage.injectable.ts delete mode 100644 packages/core/src/main/stores/init-user-store.injectable.ts delete mode 100644 packages/core/src/renderer/stores/init-user-store.injectable.ts diff --git a/packages/core/src/common/__tests__/user-store.test.ts b/packages/core/src/common/__tests__/user-store.test.ts index 1a2ca14746..eee46fa9a4 100644 --- a/packages/core/src/common/__tests__/user-store.test.ts +++ b/packages/core/src/common/__tests__/user-store.test.ts @@ -2,8 +2,6 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { UserStore } from "../user-store"; -import userStoreInjectable from "../user-store/user-store.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; import { defaultThemeId } from "../vars"; @@ -14,10 +12,16 @@ import releaseChannelInjectable from "../vars/release-channel.injectable"; import defaultUpdateChannelInjectable from "../../features/application-update/common/selected-update-channel/default-update-channel.injectable"; import writeJsonSyncInjectable from "../fs/write-json-sync.injectable"; import writeFileSyncInjectable from "../fs/write-file-sync.injectable"; +import type { UserPreferencesState } from "../../features/user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; +import userPreferencesPersistentStorageInjectable from "../../features/user-preferences/common/storage.injectable"; +import type { ResetTheme } from "../../features/user-preferences/common/reset-theme.injectable"; +import resetThemeInjectable from "../../features/user-preferences/common/reset-theme.injectable"; import type { ClusterStoreModel } from "../../features/cluster/storage/common/storage.injectable"; describe("user store tests", () => { - let userStore: UserStore; + let state: UserPreferencesState; + let resetTheme: ResetTheme; let di: DiContainer; beforeEach(async () => { @@ -33,6 +37,8 @@ describe("user store tests", () => { await di.inject(defaultUpdateChannelInjectable).init(); + state = di.inject(userPreferencesStateInjectable); + resetTheme = di.inject(resetThemeInjectable); }); describe("for an empty config", () => { @@ -42,25 +48,23 @@ describe("user store tests", () => { writeJsonSync("/some-directory-for-user-data/lens-user-store.json", {}); writeJsonSync("/some-directory-for-user-data/kube_config", {}); - userStore = di.inject(userStoreInjectable); - - userStore.load(); + di.inject(userPreferencesPersistentStorageInjectable).loadAndStartSyncing(); }); it("allows setting and getting preferences", () => { - userStore.httpsProxy = "abcd://defg"; + state.httpsProxy = "abcd://defg"; - expect(userStore.httpsProxy).toBe("abcd://defg"); - expect(userStore.colorTheme).toBe(defaultThemeId); + expect(state.httpsProxy).toBe("abcd://defg"); + expect(state.colorTheme).toBe(defaultThemeId); - userStore.colorTheme = "light"; - expect(userStore.colorTheme).toBe("light"); + state.colorTheme = "light"; + expect(state.colorTheme).toBe("light"); }); it("correctly resets theme to default value", async () => { - userStore.colorTheme = "some other theme"; - userStore.resetTheme(); - expect(userStore.colorTheme).toBe(defaultThemeId); + state.colorTheme = "some other theme"; + resetTheme(); + expect(state.colorTheme).toBe(defaultThemeId); }); }); @@ -92,18 +96,16 @@ describe("user store tests", () => { di.override(storeMigrationVersionInjectable, () => "10.0.0"); - userStore = di.inject(userStoreInjectable); - - userStore.load(); + di.inject(userPreferencesPersistentStorageInjectable).loadAndStartSyncing(); }); it("skips clusters for adding to kube-sync with files under extension_data/", () => { - expect(userStore.syncKubeconfigEntries.has("/some-directory-for-user-data/extension_data/foo/bar")).toBe(false); - expect(userStore.syncKubeconfigEntries.has("/some/other/path")).toBe(true); + expect(state.syncKubeconfigEntries.has("/some-directory-for-user-data/extension_data/foo/bar")).toBe(false); + expect(state.syncKubeconfigEntries.has("/some/other/path")).toBe(true); }); it("allows access to the colorTheme preference", () => { - expect(userStore.colorTheme).toBe("light"); + expect(state.colorTheme).toBe("light"); }); }); }); diff --git a/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts b/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts index 677c18a586..3a72ef7b12 100644 --- a/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts +++ b/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts @@ -9,7 +9,7 @@ import isProductionInjectable from "../vars/is-production.injectable"; import sentryDataSourceNameInjectable from "../vars/sentry-dsn-url.injectable"; import { Dedupe, Offline } from "@sentry/integrations"; import { inspect } from "util"; -import userStoreInjectable from "../user-store/user-store.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; export type InitializeSentryReportingWith = (initSentry: (opts: BrowserOptions | ElectronMainOptions) => void) => void; @@ -20,7 +20,7 @@ const initializeSentryReportingWithInjectable = getInjectable({ instantiate: (di): InitializeSentryReportingWith => { const sentryDataSourceName = di.inject(sentryDataSourceNameInjectable); const isProduction = di.inject(isProductionInjectable); - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); if (!sentryDataSourceName) { return () => {}; @@ -28,7 +28,7 @@ const initializeSentryReportingWithInjectable = getInjectable({ return (initSentry) => initSentry({ beforeSend: (event) => { - if (userStore.allowErrorReporting) { + if (state.allowErrorReporting) { return event; } diff --git a/packages/core/src/common/fetch/proxy-fetch.injectable.ts b/packages/core/src/common/fetch/proxy-fetch.injectable.ts index f13842c410..433670e003 100644 --- a/packages/core/src/common/fetch/proxy-fetch.injectable.ts +++ b/packages/core/src/common/fetch/proxy-fetch.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { HttpsProxyAgent } from "hpagent"; -import userStoreInjectable from "../user-store/user-store.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; import type { Fetch } from "./fetch.injectable"; import fetchInjectable from "./fetch.injectable"; @@ -12,7 +12,7 @@ const proxyFetchInjectable = getInjectable({ id: "proxy-fetch", instantiate: (di): Fetch => { const fetch = di.inject(fetchInjectable); - const { httpsProxy, allowUntrustedCAs } = di.inject(userStoreInjectable); + const { httpsProxy, allowUntrustedCAs } = di.inject(userPreferencesStateInjectable); const agent = httpsProxy ? new HttpsProxyAgent({ proxy: httpsProxy, diff --git a/packages/core/src/common/fs/fs.injectable.ts b/packages/core/src/common/fs/fs.injectable.ts index b42a51aad7..16fbbd73aa 100644 --- a/packages/core/src/common/fs/fs.injectable.ts +++ b/packages/core/src/common/fs/fs.injectable.ts @@ -22,6 +22,7 @@ const fsInjectable = getInjectable({ access, stat, unlink, + rename, }, ensureDir, ensureDirSync, @@ -58,6 +59,7 @@ const fsInjectable = getInjectable({ createReadStream, stat, unlink, + rename, }; }, causesSideEffects: true, diff --git a/packages/core/src/common/os/home-directory-path.injectable.ts b/packages/core/src/common/os/home-directory-path.injectable.ts index 83b4b0cdff..c8831eebab 100644 --- a/packages/core/src/common/os/home-directory-path.injectable.ts +++ b/packages/core/src/common/os/home-directory-path.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import userInfoInjectable from "../user-store/user-info.injectable"; +import userInfoInjectable from "../vars/user-info.injectable"; const homeDirectoryPathInjectable = getInjectable({ id: "home-directory-path", diff --git a/packages/core/src/common/user-store/file-name-migration.global-override-for-injectable.ts b/packages/core/src/common/user-store/file-name-migration.global-override-for-injectable.ts deleted file mode 100644 index 0cd1383cc6..0000000000 --- a/packages/core/src/common/user-store/file-name-migration.global-override-for-injectable.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getGlobalOverride } from "@k8slens/test-utils"; -import userStoreFileNameMigrationInjectable from "./file-name-migration.injectable"; - -export default getGlobalOverride(userStoreFileNameMigrationInjectable, () => async () => {}); diff --git a/packages/core/src/common/user-store/index.ts b/packages/core/src/common/user-store/index.ts deleted file mode 100644 index 026167519b..0000000000 --- a/packages/core/src/common/user-store/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export * from "./user-store"; -export type { KubeconfigSyncEntry, KubeconfigSyncValue, UserPreferencesModel } from "./preferences-helpers"; diff --git a/packages/core/src/common/user-store/migrations-token.ts b/packages/core/src/common/user-store/migrations-token.ts deleted file mode 100644 index 3f8cf14c9e..0000000000 --- a/packages/core/src/common/user-store/migrations-token.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getInjectionToken } from "@ogre-tools/injectable"; -import type { MigrationDeclaration } from "../persistent-storage/migrations.injectable"; - -export const userStoreMigrationInjectionToken = getInjectionToken({ - id: "user-store-migration-token", -}); diff --git a/packages/core/src/common/user-store/user-store.injectable.ts b/packages/core/src/common/user-store/user-store.injectable.ts deleted file mode 100644 index 87143d5867..0000000000 --- a/packages/core/src/common/user-store/user-store.injectable.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { UserStore } from "./user-store"; -import selectedUpdateChannelInjectable from "../../features/application-update/common/selected-update-channel/selected-update-channel.injectable"; -import emitAppEventInjectable from "../app-event-bus/emit-event.injectable"; -import loggerInjectable from "../logger.injectable"; -import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; -import persistentStorageMigrationsInjectable from "../persistent-storage/migrations.injectable"; -import { userStoreMigrationInjectionToken } from "./migrations-token"; -import userStorePreferenceDescriptorsInjectable from "./preference-descriptors.injectable"; -import createPersistentStorageInjectable from "../persistent-storage/create.injectable"; - -const userStoreInjectable = getInjectable({ - id: "user-store", - - instantiate: (di) => new UserStore({ - selectedUpdateChannel: di.inject(selectedUpdateChannelInjectable), - emitAppEvent: di.inject(emitAppEventInjectable), - logger: di.inject(loggerInjectable), - storeMigrationVersion: di.inject(storeMigrationVersionInjectable), - migrations: di.inject(persistentStorageMigrationsInjectable, userStoreMigrationInjectionToken), - preferenceDescriptors: di.inject(userStorePreferenceDescriptorsInjectable), - createPersistentStorage: di.inject(createPersistentStorageInjectable), - }), -}); - -export default userStoreInjectable; diff --git a/packages/core/src/common/user-store/user-store.ts b/packages/core/src/common/user-store/user-store.ts deleted file mode 100644 index 63f80ab146..0000000000 --- a/packages/core/src/common/user-store/user-store.ts +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { action, observable, makeObservable, isObservableArray, isObservableSet, isObservableMap, runInAction } from "mobx"; -import { getOrInsertSet, toggle, object } from "@k8slens/utilities"; -import type { UserPreferencesModel, StoreType } from "./preferences-helpers"; -import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable"; - -// TODO: Remove coupling with Feature -import type { SelectedUpdateChannel } from "../../features/application-update/common/selected-update-channel/selected-update-channel.injectable"; -import type { ReleaseChannel } from "../../features/application-update/common/update-channels"; -import type { PreferenceDescriptors } from "./preference-descriptors.injectable"; -import type { CreatePersistentStorage, PersistentStorage } from "../persistent-storage/create.injectable"; -import type { Logger } from "../logger"; -import type { Migrations } from "conf/dist/source/types"; -import { toJS } from "../utils"; - -export interface UserStoreModel { - preferences: UserPreferencesModel; -} - -interface Dependencies { - readonly selectedUpdateChannel: SelectedUpdateChannel; - readonly preferenceDescriptors: PreferenceDescriptors; - readonly logger: Logger; - readonly storeMigrationVersion: string; - readonly migrations: Migrations>; - emitAppEvent: EmitAppEvent; - createPersistentStorage: CreatePersistentStorage; -} - -export class UserStore { - private readonly store: PersistentStorage; - - constructor(protected readonly dependencies: Dependencies) { - this.store = this.dependencies.createPersistentStorage({ - configName: "lens-user-store", - projectVersion: this.dependencies.storeMigrationVersion, - migrations: this.dependencies.migrations, - fromStore: action(({ preferences }) => { - this.dependencies.logger.debug("UserStore.fromStore()", { preferences }); - - for (const [key, { fromStore }] of object.entries(this.dependencies.preferenceDescriptors)) { - const curVal = this[key]; - const newVal = fromStore((preferences)?.[key] as never) as never; - - if (isObservableArray(curVal)) { - curVal.replace(newVal); - } else if (isObservableSet(curVal) || isObservableMap(curVal)) { - curVal.replace(newVal); - } else { - this[key] = newVal; - } - } - - // TODO: Switch to action-based saving instead saving stores by reaction - if (preferences?.updateChannel) { - this.dependencies.selectedUpdateChannel.setValue(preferences?.updateChannel as ReleaseChannel); - } - }), - toJSON: () => { - const preferences = object.fromEntries( - object.entries(this.dependencies.preferenceDescriptors) - .map(([key, { toStore }]) => [key, toStore(this[key] as never)]), - ) as UserPreferencesModel; - - return toJS({ - preferences: { - ...preferences, - updateChannel: this.dependencies.selectedUpdateChannel.value.get().id, - }, - }); - }, - }); - - makeObservable(this); - } - - @observable allowErrorReporting!: StoreType; - @observable allowUntrustedCAs!: StoreType; - @observable colorTheme!: StoreType; - @observable terminalTheme!: StoreType; - @observable localeTimezone!: StoreType; - @observable downloadMirror!: StoreType; - @observable httpsProxy!: StoreType; - @observable shell!: StoreType; - @observable downloadBinariesPath!: StoreType; - @observable kubectlBinariesPath!: StoreType; - @observable terminalCopyOnSelect!: StoreType; - @observable terminalConfig!: StoreType; - @observable extensionRegistryUrl!: StoreType; - - /** - * Download kubectl binaries matching cluster version - */ - @observable downloadKubectlBinaries!: StoreType; - - /** - * Whether the application should open itself at login. - */ - @observable openAtLogin!: StoreType; - - /** - * The column IDs under each configurable table ID that have been configured - * to not be shown - */ - @observable hiddenTableColumns!: StoreType; - - /** - * Monaco editor configs - */ - @observable editorConfiguration!: StoreType; - - /** - * The set of file/folder paths to be synced - */ - @observable syncKubeconfigEntries!: StoreType; - - /** - * Checks if a column (by ID) for a table (by ID) is configured to be hidden - * @param tableId The ID of the table to be checked against - * @param columnIds The list of IDs the check if one is hidden - * @returns true if at least one column under the table is set to hidden - */ - isTableColumnHidden(tableId: string, ...columnIds: (string | undefined)[]): boolean { - if (columnIds.length === 0) { - return false; - } - - const config = this.hiddenTableColumns.get(tableId); - - if (!config) { - return false; - } - - return columnIds.some(columnId => columnId && config.has(columnId)); - } - - /** - * Toggles the hidden configuration of a table's column - */ - toggleTableColumnVisibility(tableId: string, columnId: string) { - toggle(getOrInsertSet(this.hiddenTableColumns, tableId), columnId); - } - - resetTheme() { - runInAction(() => { - this.colorTheme = this.dependencies.preferenceDescriptors.colorTheme.fromStore(undefined); - }); - } - - load() { - this.store.loadAndStartSyncing(); - } -} diff --git a/packages/core/src/common/user-store/current-timezone.global-override-for-injectable.ts b/packages/core/src/common/vars/current-timezone.global-override-for-injectable.ts similarity index 100% rename from packages/core/src/common/user-store/current-timezone.global-override-for-injectable.ts rename to packages/core/src/common/vars/current-timezone.global-override-for-injectable.ts diff --git a/packages/core/src/common/user-store/current-timezone.injectable.ts b/packages/core/src/common/vars/current-timezone.injectable.ts similarity index 100% rename from packages/core/src/common/user-store/current-timezone.injectable.ts rename to packages/core/src/common/vars/current-timezone.injectable.ts diff --git a/packages/core/src/common/user-store/user-info.global-override-for-injectable.ts b/packages/core/src/common/vars/user-info.global-override-for-injectable.ts similarity index 100% rename from packages/core/src/common/user-store/user-info.global-override-for-injectable.ts rename to packages/core/src/common/vars/user-info.global-override-for-injectable.ts diff --git a/packages/core/src/common/user-store/user-info.injectable.ts b/packages/core/src/common/vars/user-info.injectable.ts similarity index 100% rename from packages/core/src/common/user-store/user-info.injectable.ts rename to packages/core/src/common/vars/user-info.injectable.ts diff --git a/packages/core/src/extensions/common-api/app.ts b/packages/core/src/extensions/common-api/app.ts index 26bfaafef6..9e0c84f4e0 100644 --- a/packages/core/src/extensions/common-api/app.ts +++ b/packages/core/src/extensions/common-api/app.ts @@ -12,10 +12,10 @@ import { getLegacyGlobalDiForExtensionApi } from "../as-legacy-globals-for-exten import { issuesTrackerUrl } from "../../common/vars"; import { buildVersionInjectionToken } from "../../common/vars/build-semantic-version.injectable"; import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; import enabledExtensionsInjectable from "../../features/extensions/enabled/common/enabled-extensions.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; -const userStore = asLegacyGlobalForExtensionApi(userStoreInjectable); +const userStore = asLegacyGlobalForExtensionApi(userPreferencesStateInjectable); const enabledExtensions = asLegacyGlobalForExtensionApi(enabledExtensionsInjectable); export const App = { diff --git a/packages/core/src/features/cluster/storage/main/init.injectable.ts b/packages/core/src/features/cluster/storage/main/init.injectable.ts index 230357c7e2..604ed9cbbb 100644 --- a/packages/core/src/features/cluster/storage/main/init.injectable.ts +++ b/packages/core/src/features/cluster/storage/main/init.injectable.ts @@ -4,8 +4,8 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; -import initUserStoreInjectable from "../../../../main/stores/init-user-store.injectable"; import clustersPersistentStorageInjectable from "../common/storage.injectable"; +import loadUserPreferencesStorageInjectable from "../../../user-preferences/renderer/load-storage.injectable"; const initClusterStoreInjectable = getInjectable({ id: "init-cluster-store", @@ -15,7 +15,7 @@ const initClusterStoreInjectable = getInjectable({ storage.loadAndStartSyncing(); }, - runAfter: initUserStoreInjectable, + runAfter: loadUserPreferencesStorageInjectable, }), injectionToken: beforeApplicationIsLoadingInjectionToken, }); diff --git a/packages/core/src/features/cluster/storage/renderer/init.injectable.ts b/packages/core/src/features/cluster/storage/renderer/init.injectable.ts index cff2bb358b..cdedc3fceb 100644 --- a/packages/core/src/features/cluster/storage/renderer/init.injectable.ts +++ b/packages/core/src/features/cluster/storage/renderer/init.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens"; -import initUserStoreInjectable from "../../../../renderer/stores/init-user-store.injectable"; +import initUserStoreInjectable from "../../../user-preferences/renderer/load-storage.injectable"; import clustersPersistentStorageInjectable from "../common/storage.injectable"; const initClusterStoreInjectable = getInjectable({ diff --git a/packages/core/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry.tsx b/packages/core/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry.tsx index ce6aed0a5f..addd5d8a4e 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/application/extension-install-registry/extension-install-registry.tsx @@ -6,16 +6,16 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { Select } from "../../../../../../renderer/components/select"; import { withInjectables } from "@ogre-tools/injectable-react"; -import { defaultExtensionRegistryUrl, defaultExtensionRegistryUrlLocation } from "../../../../../../common/user-store/preferences-helpers"; import { Input } from "../../../../../../renderer/components/input"; import { isUrl } from "../../../../../../renderer/components/input/input_validators"; -import type { UserStore } from "../../../../../../common/user-store"; import { runInAction } from "mobx"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; +import { defaultExtensionRegistryUrlLocation, defaultExtensionRegistryUrl } from "../../../../../user-preferences/common/preferences-helpers"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } const extensionInstallRegistryOptions = [ @@ -33,8 +33,8 @@ const extensionInstallRegistryOptions = [ }, ] as const; -const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencies) => { - const [customUrl, setCustomUrl] = React.useState(userStore.extensionRegistryUrl.customUrl || ""); +const NonInjectedExtensionInstallRegistry = observer(({ state }: Dependencies) => { + const [customUrl, setCustomUrl] = React.useState(state.extensionRegistryUrl.customUrl || ""); return (
@@ -42,14 +42,14 @@ const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencie - (userStore.colorTheme = value?.value ?? defaultTheme.name) + (state.colorTheme = value?.value ?? defaultTheme.name) } themeName="lens" /> @@ -53,7 +53,7 @@ const NonInjectedTheme = observer(({ export const Theme = withInjectables(NonInjectedTheme, { getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), defaultTheme: di.inject(defaultLensThemeInjectable), themes: di.injectMany(lensThemeDeclarationInjectionToken), }), diff --git a/packages/core/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx b/packages/core/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx index c3ee8f2ea1..987f378bd9 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx @@ -5,15 +5,15 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { Select } from "../../../../../../renderer/components/select"; import moment from "moment-timezone"; import { observer } from "mobx-react"; -import currentTimezoneInjectable from "../../../../../../common/user-store/current-timezone.injectable"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import currentTimezoneInjectable from "../../../../../../common/vars/current-timezone.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; currentTimezone: string; } @@ -23,9 +23,8 @@ const timezoneOptions = moment.tz.names() label: timezone.replace("_", " "), })); - const NonInjectedTimezone = observer(({ - userStore, + state, currentTimezone, }: Dependencies) => (
@@ -33,17 +32,16 @@ const NonInjectedTimezone = observer(({ )); -export const EditorFontFamily = withInjectables( - NonInjectedEditorFontFamily, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const EditorFontFamily = withInjectables(NonInjectedEditorFontFamily, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/editor/editor-font-size/editor-font-size.tsx b/packages/core/src/features/preferences/renderer/preference-items/editor/editor-font-size/editor-font-size.tsx index 7fe83ec6aa..df144df2b7 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/editor/editor-font-size/editor-font-size.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/editor/editor-font-size/editor-font-size.tsx @@ -5,16 +5,16 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { Input, InputValidators } from "../../../../../../renderer/components/input"; import { observer } from "mobx-react"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedEditorFontSize = observer(({ userStore: { editorConfiguration }}: Dependencies) => ( +const NonInjectedEditorFontSize = observer(({ state: { editorConfiguration }}: Dependencies) => (
)); -export const EditorFontSize = withInjectables( - NonInjectedEditorFontSize, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const EditorFontSize = withInjectables(NonInjectedEditorFontSize, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/editor/line-numbers/line-numbers.tsx b/packages/core/src/features/preferences/renderer/preference-items/editor/line-numbers/line-numbers.tsx index 10cc508baa..bfd73f7415 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/editor/line-numbers/line-numbers.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/editor/line-numbers/line-numbers.tsx @@ -5,15 +5,15 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { Select } from "../../../../../../renderer/components/select"; -import { defaultEditorConfig } from "../../../../../../common/user-store/preferences-helpers"; import { capitalize } from "lodash/fp"; import { observer } from "mobx-react"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import { defaultEditorConfig } from "../../../../../user-preferences/common/preferences-helpers"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } const lineNumberOptions = ([ @@ -26,7 +26,7 @@ const lineNumberOptions = ([ label: capitalize(lineNumbers), })); -const NonInjectedLineNumbers = observer(({ userStore: { editorConfiguration }}: Dependencies) => ( +const NonInjectedLineNumbers = observer(({ state: { editorConfiguration }}: Dependencies) => (
)); -export const TabSize = withInjectables( - NonInjectedTabSize, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const TabSize = withInjectables(NonInjectedTabSize, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync.tsx b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync.tsx index 77642f1082..510fbd0115 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync.tsx @@ -7,13 +7,11 @@ import { computed, makeObservable, observable, reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import React from "react"; import { Notice } from "../../../../../../renderer/components/+extensions/notice"; -import type { UserStore } from "../../../../../../common/user-store"; import { iter, tuple } from "@k8slens/utilities"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { PathPicker } from "../../../../../../renderer/components/path-picker/path-picker"; import { Spinner } from "../../../../../../renderer/components/spinner"; import { RemovableItem } from "../../../removable-item/removable-item"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import isWindowsInjectable from "../../../../../../common/vars/is-windows.injectable"; import loggerInjectable from "../../../../../../common/logger.injectable"; import type { Logger } from "../../../../../../common/logger"; @@ -21,13 +19,15 @@ import type { DiscoverAllKubeconfigSyncKinds } from "./discover-all-sync-kinds.i import type { DiscoverKubeconfigSyncKind, SyncKind } from "./discover-sync-kind.injectable"; import discoverKubeconfigSyncKindInjectable from "./discover-sync-kind.injectable"; import discoverAllKubeconfigSyncKindsInjectable from "./discover-all-sync-kinds.injectable"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Entry extends SyncKind { filePath: string; } interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; isWindows: boolean; logger: Logger; discoverAllKubeconfigSyncKinds: DiscoverAllKubeconfigSyncKinds; @@ -47,7 +47,7 @@ class NonInjectedKubeconfigSync extends React.Component { async componentDidMount() { const mapEntries = await Promise.all( iter.map( - this.props.userStore.syncKubeconfigEntries, + this.props.state.syncKubeconfigEntries, ([filePath]) => this.props.discoverKubeconfigSyncKind(filePath), ), ); @@ -59,7 +59,7 @@ class NonInjectedKubeconfigSync extends React.Component { reaction( () => Array.from(this.syncs.entries(), ([filePath, kind]) => tuple.from(filePath, kind)), syncs => { - this.props.userStore.syncKubeconfigEntries.replace(syncs); + this.props.state.syncKubeconfigEntries.replace(syncs); }, ), ]); @@ -177,7 +177,7 @@ class NonInjectedKubeconfigSync extends React.Component { export const KubeconfigSync = withInjectables(NonInjectedKubeconfigSync, { getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), isWindows: di.inject(isWindowsInjectable), logger: di.inject(loggerInjectable), discoverAllKubeconfigSyncKinds: di.inject(discoverAllKubeconfigSyncKindsInjectable), diff --git a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-binary-download/kubectl-binary-download.tsx b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-binary-download/kubectl-binary-download.tsx index de096191fd..35d0ebff62 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-binary-download/kubectl-binary-download.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-binary-download/kubectl-binary-download.tsx @@ -5,34 +5,29 @@ import React from "react"; import { SubTitle } from "../../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Switch } from "../../../../../../../renderer/components/switch"; +import type { UserPreferencesState } from "../../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedKubectlBinaryDownload = observer(({ userStore }: Dependencies) => ( +const NonInjectedKubectlBinaryDownload = observer(({ state }: Dependencies) => (
userStore.downloadKubectlBinaries = !userStore.downloadKubectlBinaries} + checked={state.downloadKubectlBinaries} + onChange={() => state.downloadKubectlBinaries = !state.downloadKubectlBinaries} > Download kubectl binaries matching the Kubernetes cluster version
- )); -export const KubectlBinaryDownload = withInjectables( - NonInjectedKubectlBinaryDownload, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const KubectlBinaryDownload = withInjectables(NonInjectedKubectlBinaryDownload, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-directory-for-binaries/kubectl-directory-for-binaries.tsx b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-directory-for-binaries/kubectl-directory-for-binaries.tsx index 497ec68f8e..7e4bc8a2ab 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-directory-for-binaries/kubectl-directory-for-binaries.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-directory-for-binaries/kubectl-directory-for-binaries.tsx @@ -5,24 +5,24 @@ import React, { useState } from "react"; import { SubTitle } from "../../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Input, InputValidators } from "../../../../../../../renderer/components/input"; import directoryForBinariesInjectable from "../../../../../../../common/app-paths/directory-for-binaries/directory-for-binaries.injectable"; +import type { UserPreferencesState } from "../../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; defaultPathForGeneralBinaries: string; } const NonInjectedKubectlDirectoryForBinaries = observer( - ({ userStore, defaultPathForGeneralBinaries }: Dependencies) => { - const [downloadPath, setDownloadPath] = useState(userStore.downloadBinariesPath || ""); + ({ state, defaultPathForGeneralBinaries }: Dependencies) => { + const [downloadPath, setDownloadPath] = useState(state.downloadBinariesPath || ""); const pathValidator = downloadPath ? InputValidators.isPath : undefined; const save = () => { - userStore.downloadBinariesPath = downloadPath; + state.downloadBinariesPath = downloadPath; }; return ( @@ -35,7 +35,7 @@ const NonInjectedKubectlDirectoryForBinaries = observer( validators={pathValidator} onChange={setDownloadPath} onBlur={save} - disabled={!userStore.downloadKubectlBinaries} + disabled={!state.downloadKubectlBinaries} />
The directory to download binaries into.
@@ -43,13 +43,9 @@ const NonInjectedKubectlDirectoryForBinaries = observer( }, ); -export const KubectlDirectoryForBinaries = withInjectables( - NonInjectedKubectlDirectoryForBinaries, - - { - getProps: (di) => ({ - defaultPathForGeneralBinaries: di.inject(directoryForBinariesInjectable), - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const KubectlDirectoryForBinaries = withInjectables(NonInjectedKubectlDirectoryForBinaries, { + getProps: (di) => ({ + defaultPathForGeneralBinaries: di.inject(directoryForBinariesInjectable), + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-download-mirror/kubectl-download-mirror.tsx b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-download-mirror/kubectl-download-mirror.tsx index e880ff3308..7f01d8a933 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-download-mirror/kubectl-download-mirror.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-download-mirror/kubectl-download-mirror.tsx @@ -5,14 +5,14 @@ import React from "react"; import { SubTitle } from "../../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Select } from "../../../../../../../renderer/components/select"; -import { defaultPackageMirror, packageMirrors } from "../../../../../../../common/user-store/preferences-helpers"; +import { defaultPackageMirror, packageMirrors } from "../../../../../../user-preferences/common/preferences-helpers"; +import type { UserPreferencesState } from "../../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } const downloadMirrorOptions = Array.from(packageMirrors, ([name, mirror]) => ({ @@ -24,27 +24,23 @@ const downloadMirrorOptions = Array.from(packageMirrors, ([name, mirror]) => ({ })); -const NonInjectedKubectlDownloadMirror = observer(({ userStore }: Dependencies) => ( +const NonInjectedKubectlDownloadMirror = observer(({ state }: Dependencies) => (
-
- ); - }, + return ( +
+ + +
+ ); +}, ); -export const KubectlPathToBinary = withInjectables( - NonInjectedKubectlPathToBinary, - - { - getProps: (di) => ({ - defaultPathForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable), - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const KubectlPathToBinary = withInjectables(NonInjectedKubectlPathToBinary, { + getProps: (di) => ({ + defaultPathForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable), + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/proxy/allow-untrusted-certificates/allow-untrusted-certificates.tsx b/packages/core/src/features/preferences/renderer/preference-items/proxy/allow-untrusted-certificates/allow-untrusted-certificates.tsx index bb1abd9a57..eea78f6cda 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/proxy/allow-untrusted-certificates/allow-untrusted-certificates.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/proxy/allow-untrusted-certificates/allow-untrusted-certificates.tsx @@ -5,23 +5,21 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Switch } from "../../../../../../renderer/components/switch"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedAllowUntrustedCertificates = observer(({ userStore }: Dependencies) => ( +const NonInjectedAllowUntrustedCertificates = observer(({ state }: Dependencies) => (
- (userStore.allowUntrustedCAs = !userStore.allowUntrustedCAs) - } + checked={state.allowUntrustedCAs} + onChange={() => state.allowUntrustedCAs = !state.allowUntrustedCAs} > Allow untrusted Certificate Authorities @@ -33,12 +31,8 @@ const NonInjectedAllowUntrustedCertificates = observer(({ userStore }: Dependenc
)); -export const AllowUntrustedCertificates = withInjectables( - NonInjectedAllowUntrustedCertificates, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const AllowUntrustedCertificates = withInjectables(NonInjectedAllowUntrustedCertificates, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/proxy/http-proxy-url/http-proxy-url.tsx b/packages/core/src/features/preferences/renderer/preference-items/proxy/http-proxy-url/http-proxy-url.tsx index 7d55fd2b3b..9cc8e38d4b 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/proxy/http-proxy-url/http-proxy-url.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/proxy/http-proxy-url/http-proxy-url.tsx @@ -5,43 +5,39 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Input } from "../../../../../../renderer/components/input"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedHttpProxyUrl = observer( - ({ userStore }: Dependencies) => { - const [proxy, setProxy] = React.useState(userStore.httpsProxy || ""); +const NonInjectedHttpProxyUrl = observer(({ + state, +}: Dependencies) => { + const [proxy, setProxy] = React.useState(state.httpsProxy || ""); - return ( -
- - setProxy(v)} - onBlur={() => (userStore.httpsProxy = proxy)} - /> - - Proxy is used only for non-cluster communication. - -
- ); - }, -); + return ( +
+ + setProxy(v)} + onBlur={() => (state.httpsProxy = proxy)} + /> + + Proxy is used only for non-cluster communication. + +
+ ); +}); -export const HttpProxyUrl = withInjectables( - NonInjectedHttpProxyUrl, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const HttpProxyUrl = withInjectables(NonInjectedHttpProxyUrl, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/telemetry/automatic-error-reporting/automatic-error-reporting.tsx b/packages/core/src/features/preferences/renderer/preference-items/telemetry/automatic-error-reporting/automatic-error-reporting.tsx index 7e23c0af35..167189fffc 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/telemetry/automatic-error-reporting/automatic-error-reporting.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/telemetry/automatic-error-reporting/automatic-error-reporting.tsx @@ -5,16 +5,16 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Checkbox } from "../../../../../../renderer/components/checkbox"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedAutomaticErrorReporting = observer(({ userStore }: Dependencies) => ( +const NonInjectedAutomaticErrorReporting = observer(({ state }: Dependencies) => (
(userStore.allowErrorReporting = value)} + value={state.allowErrorReporting} + onChange={(value) => (state.allowErrorReporting = value)} />
@@ -36,12 +36,8 @@ const NonInjectedAutomaticErrorReporting = observer(({ userStore }: Dependencies
)); -export const AutomaticErrorReporting = withInjectables( - NonInjectedAutomaticErrorReporting, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const AutomaticErrorReporting = withInjectables(NonInjectedAutomaticErrorReporting, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx index 6fd65ccbbd..8e1f6701d8 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx @@ -5,38 +5,31 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Switch } from "../../../../../../renderer/components/switch"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedCopyPasteFromTerminal = observer( - ({ userStore }: Dependencies) => { +const NonInjectedCopyPasteFromTerminal = observer(({ + state, +}: Dependencies) => ( +
+ + state.terminalCopyOnSelect = !state.terminalCopyOnSelect} + > + Copy on select and paste on right-click + +
+)); - return ( -
- - userStore.terminalCopyOnSelect = !userStore.terminalCopyOnSelect} - > - Copy on select and paste on right-click - -
- ); - }, -); - -export const CopyPasteFromTerminal = withInjectables( - NonInjectedCopyPasteFromTerminal, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const CopyPasteFromTerminal = withInjectables(NonInjectedCopyPasteFromTerminal, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-options.injectable.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-options.injectable.tsx index 3d6a0d2ae0..ceedb3fe02 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-options.injectable.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-options.injectable.tsx @@ -7,10 +7,10 @@ import type { IComputedValue } from "mobx"; import { action, computed } from "mobx"; import React from "react"; import type { SingleValue } from "react-select"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { defaultTerminalFontFamily } from "../../../../../../common/vars"; import type { SelectOption } from "../../../../../../renderer/components/select"; import { terminalFontInjectionToken } from "../../../../../terminal/renderer/fonts/token"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; export interface TerminalFontPreferencePresenter { readonly options: IComputedValue[]>; @@ -21,7 +21,7 @@ export interface TerminalFontPreferencePresenter { const terminalFontPreferencePresenterInjectable = getInjectable({ id: "terminal-font-preference-presenter", instantiate: (di): TerminalFontPreferencePresenter => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); const terminalFonts = di.injectMany(terminalFontInjectionToken); return { @@ -30,18 +30,18 @@ const terminalFontPreferencePresenterInjectable = getInjectable({ {font.name} ), value: font.name, - isSelected: userStore.terminalConfig.fontFamily === font.name, + isSelected: state.terminalConfig.fontFamily === font.name, }))), - current: computed(() => userStore.terminalConfig.fontFamily), + current: computed(() => state.terminalConfig.fontFamily), onSelection: action(selection => { - userStore.terminalConfig.fontFamily = selection?.value ?? defaultTerminalFontFamily; + state.terminalConfig.fontFamily = selection?.value ?? defaultTerminalFontFamily; }), }; }, diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx index bf11285509..75a6a35242 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx @@ -5,40 +5,32 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Input } from "../../../../../../renderer/components/input"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedTerminalFontSize = observer( - ({ userStore }: Dependencies) => { +const NonInjectedTerminalFontSize = observer(({ + state, +}: Dependencies) => ( +
+ + state.terminalConfig.fontSize = Number(value)} /> +
+)); - return ( -
- - userStore.terminalConfig.fontSize = Number(value)} - /> -
- ); - }, -); - -export const TerminalFontSize = withInjectables( - NonInjectedTerminalFontSize, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const TerminalFontSize = withInjectables(NonInjectedTerminalFontSize, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx index 5fe14ab9df..bb5deaefe4 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx @@ -5,42 +5,35 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Input } from "../../../../../../renderer/components/input"; import defaultShellInjectable from "./default-shell/default-shell.injectable"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; defaultShell: string; } -const NonInjectedTerminalShellPath = observer( - ({ userStore, defaultShell }: Dependencies) => { +const NonInjectedTerminalShellPath = observer(({ + state, + defaultShell, +}: Dependencies) => ( +
+ + state.shell = value} + /> +
+)); - return ( -
- - userStore.shell = value} - /> -
- - ); - }, -); - -export const TerminalShellPath = withInjectables( - NonInjectedTerminalShellPath, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - defaultShell: di.inject(defaultShellInjectable), - }), - }, -); +export const TerminalShellPath = withInjectables(NonInjectedTerminalShellPath, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + defaultShell: di.inject(defaultShellInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx index bea6b1279e..5819171c8c 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx @@ -5,26 +5,25 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Select } from "../../../../../../renderer/components/select"; import type { LensTheme } from "../../../../../../renderer/themes/lens-theme"; import { lensThemeDeclarationInjectionToken } from "../../../../../../renderer/themes/declaration"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; themes: LensTheme[]; } const NonInjectedTerminalTheme = observer(({ - userStore, + state, themes, }: Dependencies) => { - const themeOptions = [ { - value: "", // TODO: replace with a sentinal value that isn't string (and serialize it differently) + value: "", // TODO: replace with a sentinel value that isn't string (and serialize it differently) label: "Match Lens Theme", }, ...themes.map(theme => ({ @@ -40,8 +39,8 @@ const NonInjectedTerminalTheme = observer(({ id="terminal-theme-input" themeName="lens" options={themeOptions} - value={userStore.terminalTheme} - onChange={option => userStore.terminalTheme = option?.value ?? ""} + value={state.terminalTheme} + onChange={option => state.terminalTheme = option?.value ?? ""} />
); @@ -50,7 +49,7 @@ const NonInjectedTerminalTheme = observer(({ export const TerminalTheme = withInjectables(NonInjectedTerminalTheme, { getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), themes: di.injectMany(lensThemeDeclarationInjectionToken), }), }); diff --git a/packages/core/src/features/shell-sync/main/setup-shell.injectable.ts b/packages/core/src/features/shell-sync/main/setup-shell.injectable.ts index 3a763b7426..f7a8b65974 100644 --- a/packages/core/src/features/shell-sync/main/setup-shell.injectable.ts +++ b/packages/core/src/features/shell-sync/main/setup-shell.injectable.ts @@ -8,9 +8,9 @@ import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; import isSnapPackageInjectable from "../../../common/vars/is-snap-package.injectable"; import electronAppInjectable from "../../../main/electron-app/electron-app.injectable"; import computeShellEnvironmentInjectable from "./compute-shell-environment.injectable"; -import userShellSettingInjectable from "../../../common/user-store/shell-setting.injectable"; import emitShellSyncFailedInjectable from "./emit-failure.injectable"; import { unionPATHs } from "@k8slens/utilities"; +import userShellSettingInjectable from "../../user-preferences/common/shell-setting.injectable"; const setupShellInjectable = getInjectable({ id: "setup-shell", diff --git a/packages/core/src/features/theme/system-type/renderer/initialize.injectable.ts b/packages/core/src/features/theme/system-type/renderer/initialize.injectable.ts index 2e09f8e9d1..ea22b5420b 100644 --- a/packages/core/src/features/theme/system-type/renderer/initialize.injectable.ts +++ b/packages/core/src/features/theme/system-type/renderer/initialize.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens"; -import initUserStoreInjectable from "../../../../renderer/stores/init-user-store.injectable"; +import initUserStoreInjectable from "../../../user-preferences/renderer/load-storage.injectable"; import systemThemeConfigurationInjectable from "../../../../renderer/themes/system-theme.injectable"; import requestInitialSystemThemeTypeInjectable from "./request-initial.injectable"; diff --git a/packages/core/src/common/user-store/https-proxy.injectable.ts b/packages/core/src/features/user-preferences/common/https-proxy.injectable.ts similarity index 78% rename from packages/core/src/common/user-store/https-proxy.injectable.ts rename to packages/core/src/features/user-preferences/common/https-proxy.injectable.ts index 30569d4e77..c582617c17 100644 --- a/packages/core/src/common/user-store/https-proxy.injectable.ts +++ b/packages/core/src/features/user-preferences/common/https-proxy.injectable.ts @@ -4,12 +4,12 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; const httpsProxyConfigurationInjectable = getInjectable({ id: "https-proxy-configuration", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const userStore = di.inject(userPreferencesStateInjectable); return computed(() => userStore.httpsProxy); }, diff --git a/packages/core/src/features/user-preferences/common/is-table-column-hidden.injectable.ts b/packages/core/src/features/user-preferences/common/is-table-column-hidden.injectable.ts new file mode 100644 index 0000000000..f1e3d72318 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/is-table-column-hidden.injectable.ts @@ -0,0 +1,38 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getInjectable } from "@ogre-tools/injectable"; +import userPreferencesStateInjectable from "./state.injectable"; + +/** + * Checks if a column (by ID) for a table (by ID) is configured to be hidden + * @param tableId The ID of the table to be checked against + * @param columnIds The list of IDs the check if one is hidden + * @returns true if at least one column under the table is set to hidden + */ +export type IsTableColumnHidden = (tableId: string, ...columnIds: (string | undefined)[]) => boolean; + +const isTableColumnHiddenInjectable = getInjectable({ + id: "is-table-column-hidden", + instantiate: (di): IsTableColumnHidden => { + const state = di.inject(userPreferencesStateInjectable); + + return (tableId, ...columnIds) => { + if (columnIds.length === 0) { + return false; + } + + const config = state.hiddenTableColumns.get(tableId); + + if (!config) { + return false; + } + + return columnIds.some(columnId => columnId && config.has(columnId)); + }; + }, +}); + +export default isTableColumnHiddenInjectable; diff --git a/packages/core/src/common/user-store/kubeconfig-syncs.injectable.ts b/packages/core/src/features/user-preferences/common/kubeconfig-syncs.injectable.ts similarity index 68% rename from packages/core/src/common/user-store/kubeconfig-syncs.injectable.ts rename to packages/core/src/features/user-preferences/common/kubeconfig-syncs.injectable.ts index 7327b9d8e4..db34b53c1f 100644 --- a/packages/core/src/common/user-store/kubeconfig-syncs.injectable.ts +++ b/packages/core/src/features/user-preferences/common/kubeconfig-syncs.injectable.ts @@ -3,11 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; const kubeconfigSyncsInjectable = getInjectable({ id: "kubeconfig-syncs", - instantiate: (di) => di.inject(userStoreInjectable).syncKubeconfigEntries, + instantiate: (di) => di.inject(userPreferencesStateInjectable).syncKubeconfigEntries, }); export default kubeconfigSyncsInjectable; diff --git a/packages/core/src/common/user-store/lens-color-theme.injectable.ts b/packages/core/src/features/user-preferences/common/lens-color-theme.injectable.ts similarity index 78% rename from packages/core/src/common/user-store/lens-color-theme.injectable.ts rename to packages/core/src/features/user-preferences/common/lens-color-theme.injectable.ts index 5b48de1a37..1ed2930a37 100644 --- a/packages/core/src/common/user-store/lens-color-theme.injectable.ts +++ b/packages/core/src/features/user-preferences/common/lens-color-theme.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; export type LensColorThemePreference = { useSystemTheme: true; @@ -16,11 +16,11 @@ export type LensColorThemePreference = { const lensColorThemePreferenceInjectable = getInjectable({ id: "lens-color-theme-preference", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); return computed((): LensColorThemePreference => { // TODO: remove magic strings - if (userStore.colorTheme === "system") { + if (state.colorTheme === "system") { return { useSystemTheme: true, }; @@ -28,7 +28,7 @@ const lensColorThemePreferenceInjectable = getInjectable({ return { useSystemTheme: false, - lensThemeId: userStore.colorTheme, + lensThemeId: state.colorTheme, }; }); }, diff --git a/packages/core/src/features/user-preferences/common/migrations-token.ts b/packages/core/src/features/user-preferences/common/migrations-token.ts new file mode 100644 index 0000000000..0da426e3e6 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/migrations-token.ts @@ -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 "../../../common/persistent-storage/migrations.injectable"; + +export const userPreferencesMigrationInjectionToken = getInjectionToken({ + id: "user-preferences-migration-token", +}); diff --git a/packages/core/src/common/user-store/preference-descriptors.injectable.ts b/packages/core/src/features/user-preferences/common/preference-descriptors.injectable.ts similarity index 89% rename from packages/core/src/common/user-store/preference-descriptors.injectable.ts rename to packages/core/src/features/user-preferences/common/preference-descriptors.injectable.ts index 35815dbbea..afb84cb892 100644 --- a/packages/core/src/common/user-store/preference-descriptors.injectable.ts +++ b/packages/core/src/features/user-preferences/common/preference-descriptors.injectable.ts @@ -6,17 +6,17 @@ import { getInjectable } from "@ogre-tools/injectable"; import { merge } from "lodash"; import type { ObservableMap } from "mobx"; import { observable } from "mobx"; -import homeDirectoryPathInjectable from "../os/home-directory-path.injectable"; -import joinPathsInjectable from "../path/join-paths.injectable"; -import { defaultThemeId } from "../vars"; -import currentTimezoneInjectable from "./current-timezone.injectable"; +import homeDirectoryPathInjectable from "../../../common/os/home-directory-path.injectable"; +import joinPathsInjectable from "../../../common/path/join-paths.injectable"; +import { defaultThemeId } from "../../../common/vars"; +import currentTimezoneInjectable from "../../../common/vars/current-timezone.injectable"; import type { EditorConfiguration, ExtensionRegistry, KubeconfigSyncEntry, KubeconfigSyncValue, TerminalConfig } from "./preferences-helpers"; import { defaultExtensionRegistryUrlLocation, defaultEditorConfig, defaultTerminalConfig, defaultPackageMirror, getPreferenceDescriptor, packageMirrors } from "./preferences-helpers"; -export type PreferenceDescriptors = ReturnType; +export type PreferenceDescriptors = ReturnType; -const userStorePreferenceDescriptorsInjectable = getInjectable({ - id: "user-store-preference-descriptors", +const userPreferenceDescriptorsInjectable = getInjectable({ + id: "user-preference-descriptors", instantiate: (di) => { const currentTimezone = di.inject(currentTimezoneInjectable); const joinPaths = di.inject(joinPathsInjectable); @@ -140,4 +140,4 @@ const userStorePreferenceDescriptorsInjectable = getInjectable({ }, }); -export default userStorePreferenceDescriptorsInjectable; +export default userPreferenceDescriptorsInjectable; diff --git a/packages/core/src/common/user-store/preferences-helpers.ts b/packages/core/src/features/user-preferences/common/preferences-helpers.ts similarity index 94% rename from packages/core/src/common/user-store/preferences-helpers.ts rename to packages/core/src/features/user-preferences/common/preferences-helpers.ts index ecb9108bee..1a80dccd28 100644 --- a/packages/core/src/common/user-store/preferences-helpers.ts +++ b/packages/core/src/features/user-preferences/common/preferences-helpers.ts @@ -4,7 +4,7 @@ */ import type { editor } from "monaco-editor"; -import { defaultEditorFontFamily, defaultFontSize, defaultTerminalFontFamily } from "../vars"; +import { defaultFontSize, defaultTerminalFontFamily, defaultEditorFontFamily } from "../../../common/vars"; import type { PreferenceDescriptors } from "./preference-descriptors.injectable"; export interface KubeconfigSyncEntry extends KubeconfigSyncValue { @@ -95,5 +95,5 @@ export type UserStoreFlatModel = { }; export type UserPreferencesModel = { - [field in keyof PreferenceDescriptors]: PreferencesModelType; + [field in keyof PreferenceDescriptors]?: PreferencesModelType; } & { updateChannel: string }; diff --git a/packages/core/src/features/user-preferences/common/reset-theme.injectable.ts b/packages/core/src/features/user-preferences/common/reset-theme.injectable.ts new file mode 100644 index 0000000000..cdff170946 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/reset-theme.injectable.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { action } from "mobx"; +import userPreferenceDescriptorsInjectable from "./preference-descriptors.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; + +export type ResetTheme = () => void; + +const resetThemeInjectable = getInjectable({ + id: "reset-theme", + instantiate: (di): ResetTheme => { + const state = di.inject(userPreferencesStateInjectable); + const preferenceDescriptors = di.inject(userPreferenceDescriptorsInjectable); + + return action(() => { + state.colorTheme = preferenceDescriptors.colorTheme.fromStore(undefined); + }); + }, +}); + +export default resetThemeInjectable; diff --git a/packages/core/src/common/user-store/shell-setting.injectable.ts b/packages/core/src/features/user-preferences/common/shell-setting.injectable.ts similarity index 63% rename from packages/core/src/common/user-store/shell-setting.injectable.ts rename to packages/core/src/features/user-preferences/common/shell-setting.injectable.ts index f93a4e5874..a4f7a42585 100644 --- a/packages/core/src/common/user-store/shell-setting.injectable.ts +++ b/packages/core/src/features/user-preferences/common/shell-setting.injectable.ts @@ -4,16 +4,16 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userInfoInjectable from "./user-info.injectable"; -import userStoreInjectable from "./user-store.injectable"; +import userInfoInjectable from "../../../common/vars/user-info.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; const userShellSettingInjectable = getInjectable({ id: "user-shell-setting", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); const userInfo = di.inject(userInfoInjectable); - return computed(() => userStore.shell || userInfo.shell); + return computed(() => state.shell || userInfo.shell); }, }); diff --git a/packages/core/src/features/user-preferences/common/state.injectable.ts b/packages/core/src/features/user-preferences/common/state.injectable.ts new file mode 100644 index 0000000000..53f4ac0356 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/state.injectable.ts @@ -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 { observable } from "mobx"; +import type { PreferenceDescriptors } from "./preference-descriptors.injectable"; +import type { StoreType } from "./preferences-helpers"; + +export type UserPreferencesState = { + -readonly [Field in keyof PreferenceDescriptors]: StoreType; +}; + +const userPreferencesStateInjectable = getInjectable({ + id: "user-preferences-state", + instantiate: () => observable.object({} as UserPreferencesState), +}); + +export default userPreferencesStateInjectable; diff --git a/packages/core/src/features/user-preferences/common/storage.injectable.ts b/packages/core/src/features/user-preferences/common/storage.injectable.ts new file mode 100644 index 0000000000..d736c28677 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/storage.injectable.ts @@ -0,0 +1,88 @@ +/** + * 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 { action } from "mobx"; +import prefixedLoggerInjectable from "../../../common/logger/prefixed-logger.injectable"; +import createPersistentStorageInjectable from "../../../common/persistent-storage/create.injectable"; +import persistentStorageMigrationsInjectable from "../../../common/persistent-storage/migrations.injectable"; +import { userPreferencesMigrationInjectionToken } from "./migrations-token"; +import { toJS } from "../../../common/utils"; +import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable"; +import selectedUpdateChannelInjectable from "../../application-update/common/selected-update-channel/selected-update-channel.injectable"; +import type { ReleaseChannel } from "../../application-update/common/update-channels"; +import userPreferencesStateInjectable from "./state.injectable"; +import userPreferenceDescriptorsInjectable from "./preference-descriptors.injectable"; +import type { UserPreferencesModel } from "./preferences-helpers"; + +export interface UserStoreModel { + preferences: UserPreferencesModel; +} + +const userPreferencesPersistentStorageInjectable = getInjectable({ + id: "user-preferences-persistent-storage", + instantiate: (di) => { + const createPersistentStorage = di.inject(createPersistentStorageInjectable); + const logger = di.inject(prefixedLoggerInjectable, "USER-PREFERENCES"); + const descriptors = di.inject(userPreferenceDescriptorsInjectable); + const selectedUpdateChannel = di.inject(selectedUpdateChannelInjectable); + const state = di.inject(userPreferencesStateInjectable); + + return createPersistentStorage({ + configName: "lens-user-store", + projectVersion: di.inject(storeMigrationVersionInjectable), + migrations: di.inject(persistentStorageMigrationsInjectable, userPreferencesMigrationInjectionToken), + fromStore: action(({ preferences = {}}) => { + logger.debug("fromStore()", { preferences }); + + state.allowErrorReporting = descriptors.allowErrorReporting.fromStore(preferences.allowErrorReporting); + state.allowUntrustedCAs = descriptors.allowUntrustedCAs.fromStore(preferences.allowUntrustedCAs); + state.colorTheme = descriptors.colorTheme.fromStore(preferences.colorTheme); + state.downloadBinariesPath = descriptors.downloadBinariesPath.fromStore(preferences.downloadBinariesPath); + state.downloadKubectlBinaries = descriptors.downloadKubectlBinaries.fromStore(preferences.downloadKubectlBinaries); + state.downloadMirror = descriptors.downloadMirror.fromStore(preferences.downloadMirror); + state.editorConfiguration = descriptors.editorConfiguration.fromStore(preferences.editorConfiguration); + state.extensionRegistryUrl = descriptors.extensionRegistryUrl.fromStore(preferences.extensionRegistryUrl); + state.hiddenTableColumns = descriptors.hiddenTableColumns.fromStore(preferences.hiddenTableColumns); + state.httpsProxy = descriptors.httpsProxy.fromStore(preferences.httpsProxy); + state.kubectlBinariesPath = descriptors.kubectlBinariesPath.fromStore(preferences.kubectlBinariesPath); + state.localeTimezone = descriptors.localeTimezone.fromStore(preferences.localeTimezone); + state.openAtLogin = descriptors.openAtLogin.fromStore(preferences.openAtLogin); + state.shell = descriptors.shell.fromStore(preferences.shell); + state.syncKubeconfigEntries = descriptors.syncKubeconfigEntries.fromStore(preferences.syncKubeconfigEntries); + state.terminalConfig = descriptors.terminalConfig.fromStore(preferences.terminalConfig); + state.terminalCopyOnSelect = descriptors.terminalCopyOnSelect.fromStore(preferences.terminalCopyOnSelect); + state.terminalTheme = descriptors.terminalTheme.fromStore(preferences.terminalTheme); + + // TODO: Switch to action-based saving instead saving stores by reaction + selectedUpdateChannel.setValue(preferences?.updateChannel as ReleaseChannel); + }), + toJSON: () => toJS({ + preferences: { + allowErrorReporting: descriptors.allowErrorReporting.toStore(state.allowErrorReporting), + allowUntrustedCAs: descriptors.allowUntrustedCAs.toStore(state.allowUntrustedCAs), + colorTheme: descriptors.colorTheme.toStore(state.colorTheme), + downloadBinariesPath: descriptors.downloadBinariesPath.toStore(state.downloadBinariesPath), + downloadKubectlBinaries: descriptors.downloadKubectlBinaries.toStore(state.downloadKubectlBinaries), + downloadMirror: descriptors.downloadMirror.toStore(state.downloadMirror), + editorConfiguration: descriptors.editorConfiguration.toStore(state.editorConfiguration), + extensionRegistryUrl: descriptors.extensionRegistryUrl.toStore(state.extensionRegistryUrl), + hiddenTableColumns: descriptors.hiddenTableColumns.toStore(state.hiddenTableColumns), + httpsProxy: descriptors.httpsProxy.toStore(state.httpsProxy), + kubectlBinariesPath: descriptors.kubectlBinariesPath.toStore(state.kubectlBinariesPath), + localeTimezone: descriptors.localeTimezone.toStore(state.localeTimezone), + openAtLogin: descriptors.openAtLogin.toStore(state.openAtLogin), + shell: descriptors.shell.toStore(state.shell), + syncKubeconfigEntries: descriptors.syncKubeconfigEntries.toStore(state.syncKubeconfigEntries), + terminalConfig: descriptors.terminalConfig.toStore(state.terminalConfig), + terminalCopyOnSelect: descriptors.terminalCopyOnSelect.toStore(state.terminalCopyOnSelect), + terminalTheme: descriptors.terminalTheme.toStore(state.terminalTheme), + updateChannel: selectedUpdateChannel.value.get().id, + }, + }), + }); + }, +}); + +export default userPreferencesPersistentStorageInjectable; diff --git a/packages/core/src/common/user-store/terminal-config.injectable.ts b/packages/core/src/features/user-preferences/common/terminal-config.injectable.ts similarity index 60% rename from packages/core/src/common/user-store/terminal-config.injectable.ts rename to packages/core/src/features/user-preferences/common/terminal-config.injectable.ts index 6f5be75eaf..cfa9cffb3c 100644 --- a/packages/core/src/common/user-store/terminal-config.injectable.ts +++ b/packages/core/src/features/user-preferences/common/terminal-config.injectable.ts @@ -3,16 +3,15 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { computed } from "mobx"; -import { toJS } from "../utils"; -import userStoreInjectable from "./user-store.injectable"; +import { computed, toJS } from "mobx"; +import userPreferencesStateInjectable from "./state.injectable"; const terminalConfigInjectable = getInjectable({ id: "terminal-config", instantiate: (di) => { - const store = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); - return computed(() => toJS(store.terminalConfig)); + return computed(() => toJS(state.terminalConfig)); }, }); diff --git a/packages/core/src/common/user-store/terminal-copy-on-select.injectable.ts b/packages/core/src/features/user-preferences/common/terminal-copy-on-select.injectable.ts similarity index 69% rename from packages/core/src/common/user-store/terminal-copy-on-select.injectable.ts rename to packages/core/src/features/user-preferences/common/terminal-copy-on-select.injectable.ts index 543a4f73b9..494b43039a 100644 --- a/packages/core/src/common/user-store/terminal-copy-on-select.injectable.ts +++ b/packages/core/src/features/user-preferences/common/terminal-copy-on-select.injectable.ts @@ -4,14 +4,14 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; const terminalCopyOnSelectInjectable = getInjectable({ id: "terminal-copy-on-select", instantiate: (di) => { - const store = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); - return computed(() => store.terminalCopyOnSelect); + return computed(() => state.terminalCopyOnSelect); }, }); diff --git a/packages/core/src/common/user-store/terminal-theme.injectable.ts b/packages/core/src/features/user-preferences/common/terminal-theme.injectable.ts similarity index 79% rename from packages/core/src/common/user-store/terminal-theme.injectable.ts rename to packages/core/src/features/user-preferences/common/terminal-theme.injectable.ts index a0a00c3253..f9e5c6d6f5 100644 --- a/packages/core/src/common/user-store/terminal-theme.injectable.ts +++ b/packages/core/src/features/user-preferences/common/terminal-theme.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; export type TerminalThemePreference = { matchLensTheme: true; @@ -16,11 +16,11 @@ export type TerminalThemePreference = { const terminalThemePreferenceInjectable = getInjectable({ id: "terminal-theme-preference", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); return computed((): TerminalThemePreference => { // NOTE: remove use of magic strings - if (!userStore.terminalTheme) { + if (!state.terminalTheme) { return { matchLensTheme: true, }; @@ -28,7 +28,7 @@ const terminalThemePreferenceInjectable = getInjectable({ return { matchLensTheme: false, - themeId: userStore.terminalTheme, + themeId: state.terminalTheme, }; }); }, diff --git a/packages/core/src/features/user-preferences/common/toggle-table-column-visibility.injectable.ts b/packages/core/src/features/user-preferences/common/toggle-table-column-visibility.injectable.ts new file mode 100644 index 0000000000..94d1d07701 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/toggle-table-column-visibility.injectable.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getOrInsertSet, toggle } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import { action } from "mobx"; +import userPreferencesStateInjectable from "./state.injectable"; + +export type ToggleTableColumnVisibility = (tableId: string, columnId: string) => void; + +const toggleTableColumnVisibilityInjectable = getInjectable({ + id: "toggle-table-column-visibility", + instantiate: (di): ToggleTableColumnVisibility => { + const state = di.inject(userPreferencesStateInjectable); + + return action((tableId, columnId) => { + toggle(getOrInsertSet(state.hiddenTableColumns, tableId), columnId); + }); + }, +}); + +export default toggleTableColumnVisibilityInjectable; diff --git a/packages/core/src/main/user-store/migrations/5.0.0-alpha.3.injectable.ts b/packages/core/src/features/user-preferences/main/5.0.0-alpha.3.injectable.ts similarity index 70% rename from packages/core/src/main/user-store/migrations/5.0.0-alpha.3.injectable.ts rename to packages/core/src/features/user-preferences/main/5.0.0-alpha.3.injectable.ts index 617f32ad5d..70127386cb 100644 --- a/packages/core/src/main/user-store/migrations/5.0.0-alpha.3.injectable.ts +++ b/packages/core/src/features/user-preferences/main/5.0.0-alpha.3.injectable.ts @@ -5,14 +5,14 @@ // Switch representation of hiddenTableColumns in store import { getInjectable } from "@ogre-tools/injectable"; -import { userStoreMigrationInjectionToken } from "../../../common/user-store/migrations-token"; +import { userPreferencesMigrationInjectionToken } from "../common/migrations-token"; interface PreV500Alpha3UserPreferencesModel { hiddenTableColumns?: Record; } -const v500Alpha3UserStoreMigrationInjectable = getInjectable({ - id: "v5.0.0-alpha.3-user-store-migration", +const v500Alpha3UserPreferencesStorageMigrationInjectable = getInjectable({ + id: "v5.0.0-alpha.3-preferences-storage-migration", instantiate: () => ({ version: "5.0.0-alpha.3", run(store) { @@ -29,8 +29,8 @@ const v500Alpha3UserStoreMigrationInjectable = getInjectable({ }); }, }), - injectionToken: userStoreMigrationInjectionToken, + injectionToken: userPreferencesMigrationInjectionToken, }); -export default v500Alpha3UserStoreMigrationInjectable; +export default v500Alpha3UserPreferencesStorageMigrationInjectable; diff --git a/packages/core/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts b/packages/core/src/features/user-preferences/main/5.0.3-beta.1.injectable.ts similarity index 89% rename from packages/core/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts rename to packages/core/src/features/user-preferences/main/5.0.3-beta.1.injectable.ts index 66a324f87c..d7baa496b0 100644 --- a/packages/core/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts +++ b/packages/core/src/features/user-preferences/main/5.0.3-beta.1.injectable.ts @@ -3,7 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../../common/user-store"; import { isErrnoException } from "@k8slens/utilities"; import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable"; @@ -11,15 +10,16 @@ import joinPathsInjectable from "../../../common/path/join-paths.injectable"; import isLogicalChildPathInjectable from "../../../common/path/is-logical-child-path.injectable"; import getDirnameOfPathInjectable from "../../../common/path/get-dirname.injectable"; import { getInjectable } from "@ogre-tools/injectable"; -import { userStoreMigrationInjectionToken } from "../../../common/user-store/migrations-token"; +import { userPreferencesMigrationInjectionToken } from "../../../features/user-preferences/common/migrations-token"; import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable"; import homeDirectoryPathInjectable from "../../../common/os/home-directory-path.injectable"; import loggerInjectable from "../../../common/logger.injectable"; import pathExistsSyncInjectable from "../../../common/fs/path-exists-sync.injectable"; import type { ClusterStoreModel } from "../../../features/cluster/storage/common/storage.injectable"; +import type { UserPreferencesModel, KubeconfigSyncEntry } from "../common/preferences-helpers"; -const v503Beta1UserStoreMigrationInjectable = getInjectable({ - id: "v5.0.3-beta.1-user-store-migration", +const v503Beta1UserPreferencesStorageMigrationInjectable = getInjectable({ + id: "v5.0.3-beta.1-preferences-storage-migration", instantiate: (di) => { const userDataPath = di.inject(directoryForUserDataInjectable); const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable); @@ -85,7 +85,7 @@ const v503Beta1UserStoreMigrationInjectable = getInjectable({ }, }; }, - injectionToken: userStoreMigrationInjectionToken, + injectionToken: userPreferencesMigrationInjectionToken, }); -export default v503Beta1UserStoreMigrationInjectable; +export default v503Beta1UserPreferencesStorageMigrationInjectable; diff --git a/packages/core/src/common/user-store/file-name-migration.injectable.ts b/packages/core/src/features/user-preferences/main/file-name-migration.injectable.ts similarity index 64% rename from packages/core/src/common/user-store/file-name-migration.injectable.ts rename to packages/core/src/features/user-preferences/main/file-name-migration.injectable.ts index 31d5352056..e474e7f5c6 100644 --- a/packages/core/src/common/user-store/file-name-migration.injectable.ts +++ b/packages/core/src/features/user-preferences/main/file-name-migration.injectable.ts @@ -3,28 +3,29 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import fse from "fs-extra"; -import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import { isErrnoException } from "@k8slens/utilities"; import { getInjectable } from "@ogre-tools/injectable"; -import joinPathsInjectable from "../path/join-paths.injectable"; +import joinPathsInjectable from "../../../common/path/join-paths.injectable"; +import fsInjectable from "../../../common/fs/fs.injectable"; export type UserStoreFileNameMigration = () => Promise; -const userStoreFileNameMigrationInjectable = getInjectable({ - id: "user-store-file-name-migration", +const userPreferencesStorageFileNameMigrationInjectable = getInjectable({ + id: "preferences-storage-file-name-migration", instantiate: (di): UserStoreFileNameMigration => { const userDataPath = di.inject(directoryForUserDataInjectable); const joinPaths = di.inject(joinPathsInjectable); const configJsonPath = joinPaths(userDataPath, "config.json"); const lensUserStoreJsonPath = joinPaths(userDataPath, "lens-user-store.json"); + const { rename, rm } = di.inject(fsInjectable); return async () => { try { - await fse.move(configJsonPath, lensUserStoreJsonPath); + await rename(configJsonPath, lensUserStoreJsonPath); } catch (error) { if (error instanceof Error && error.message === "dest already exists.") { - await fse.remove(configJsonPath); + await rm(configJsonPath); } else if (isErrnoException(error) && error.code === "ENOENT" && error.path === configJsonPath) { // (No such file or directory) return; // file already moved @@ -35,7 +36,6 @@ const userStoreFileNameMigrationInjectable = getInjectable({ } }; }, - causesSideEffects: true, }); -export default userStoreFileNameMigrationInjectable; +export default userPreferencesStorageFileNameMigrationInjectable; diff --git a/packages/core/src/features/user-preferences/main/load-storage.injectable.ts b/packages/core/src/features/user-preferences/main/load-storage.injectable.ts new file mode 100644 index 0000000000..bde6cc4617 --- /dev/null +++ b/packages/core/src/features/user-preferences/main/load-storage.injectable.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; +import initDefaultUpdateChannelInjectable from "../../../renderer/vars/default-update-channel/init.injectable"; +import userPreferencesPersistentStorageInjectable from "../common/storage.injectable"; +import userPreferencesStorageFileNameMigrationInjectable from "./file-name-migration.injectable"; + +const loadUserPreferencesStorageInjectable = getInjectable({ + id: "load-user-preferences-storage", + instantiate: (di) => ({ + run: async () => { + const storage = di.inject(userPreferencesPersistentStorageInjectable); + const userStoreFileNameMigration = di.inject(userPreferencesStorageFileNameMigrationInjectable); + + await userStoreFileNameMigration(); + storage.loadAndStartSyncing(); + }, + runAfter: initDefaultUpdateChannelInjectable, + }), + injectionToken: beforeApplicationIsLoadingInjectionToken, +}); + +export default loadUserPreferencesStorageInjectable; diff --git a/packages/core/src/main/user-store/sync-open-at-login-with-os.injectable.ts b/packages/core/src/features/user-preferences/main/sync-open-at-login-with-os.injectable.ts similarity index 72% rename from packages/core/src/main/user-store/sync-open-at-login-with-os.injectable.ts rename to packages/core/src/features/user-preferences/main/sync-open-at-login-with-os.injectable.ts index a06d65163e..41f3dff55c 100644 --- a/packages/core/src/main/user-store/sync-open-at-login-with-os.injectable.ts +++ b/packages/core/src/features/user-preferences/main/sync-open-at-login-with-os.injectable.ts @@ -4,18 +4,18 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { reaction } from "mobx"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; -import setLoginItemSettingsInjectable from "../electron-app/features/set-login-item-settings.injectable"; +import setLoginItemSettingsInjectable from "../../../main/electron-app/features/set-login-item-settings.injectable"; import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; +import userPreferencesStateInjectable from "../common/state.injectable"; const setupSyncOpenAtLoginWithOsInjectable = getInjectable({ id: "setup-sync-open-at-login-with-os", instantiate: (di) => ({ run: () => { const setLoginItemSettings = di.inject(setLoginItemSettingsInjectable); - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); - reaction(() => userStore.openAtLogin, openAtLogin => { + reaction(() => state.openAtLogin, openAtLogin => { setLoginItemSettings({ openAtLogin, openAsHidden: true, diff --git a/packages/core/src/features/user-preferences/renderer/load-storage.injectable.ts b/packages/core/src/features/user-preferences/renderer/load-storage.injectable.ts new file mode 100644 index 0000000000..43e10c1707 --- /dev/null +++ b/packages/core/src/features/user-preferences/renderer/load-storage.injectable.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { beforeFrameStartsSecondInjectionToken } from "../../../renderer/before-frame-starts/tokens"; +import initDefaultUpdateChannelInjectable from "../../../renderer/vars/default-update-channel/init.injectable"; +import userPreferencesPersistentStorageInjectable from "../common/storage.injectable"; + +const loadUserPreferencesStorageInjectable = getInjectable({ + id: "load-user-preferences-storage", + instantiate: (di) => ({ + run: () => { + const storage = di.inject(userPreferencesPersistentStorageInjectable); + + return storage.loadAndStartSyncing(); + }, + runAfter: initDefaultUpdateChannelInjectable, + }), + injectionToken: beforeFrameStartsSecondInjectionToken, +}); + +export default loadUserPreferencesStorageInjectable; diff --git a/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts b/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts index 9625d7399c..6d23610e79 100644 --- a/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts +++ b/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts @@ -17,8 +17,6 @@ import type { ConfigToModels } from "../kubeconfig-sync/config-to-models.injecta import configToModelsInjectable from "../kubeconfig-sync/config-to-models.injectable"; import kubeconfigSyncManagerInjectable from "../kubeconfig-sync/manager.injectable"; import type { KubeconfigSyncManager } from "../kubeconfig-sync/manager"; -import type { KubeconfigSyncValue } from "../../../common/user-store"; -import kubeconfigSyncsInjectable from "../../../common/user-store/kubeconfig-syncs.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; import type { AsyncFnMock } from "@async-fn/jest"; import type { Stat } from "../../../common/fs/stat.injectable"; @@ -35,6 +33,8 @@ import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable"; import type { KubeconfigManager } from "../../kubeconfig-manager/kubeconfig-manager"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; +import type { KubeconfigSyncValue } from "../../../features/user-preferences/common/preferences-helpers"; +import kubeconfigSyncsInjectable from "../../../features/user-preferences/common/kubeconfig-syncs.injectable"; describe("kubeconfig-sync.source tests", () => { let computeKubeconfigDiff: ComputeKubeconfigDiff; diff --git a/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.injectable.ts b/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.injectable.ts index 06265764c8..9160df83da 100644 --- a/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.injectable.ts +++ b/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.injectable.ts @@ -7,7 +7,7 @@ import directoryForKubeConfigsInjectable from "../../../common/app-paths/directo import { KubeconfigSyncManager } from "./manager"; import kubeconfigSyncLoggerInjectable from "./logger.injectable"; import watchKubeconfigFileChangesInjectable from "./watch-file-changes.injectable"; -import kubeconfigSyncsInjectable from "../../../common/user-store/kubeconfig-syncs.injectable"; +import kubeconfigSyncsInjectable from "../../../features/user-preferences/common/kubeconfig-syncs.injectable"; const kubeconfigSyncManagerInjectable = getInjectable({ id: "kubeconfig-sync-manager", diff --git a/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.ts b/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.ts index 77ef96b765..c7b53d8973 100644 --- a/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.ts +++ b/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.ts @@ -8,9 +8,9 @@ import { action, observable, computed, makeObservable, observe } from "mobx"; import type { CatalogEntity } from "../../../common/catalog"; import type { Disposer } from "@k8slens/utilities"; import { iter } from "@k8slens/utilities"; -import type { KubeconfigSyncValue } from "../../../common/user-store"; import type { Logger } from "../../../common/logger"; import type { WatchKubeconfigFileChanges } from "./watch-file-changes.injectable"; +import type { KubeconfigSyncValue } from "../../../features/user-preferences/common/preferences-helpers"; interface KubeconfigSyncManagerDependencies { readonly directoryForKubeConfigs: string; diff --git a/packages/core/src/main/helm/exec-helm/exec-env.injectable.ts b/packages/core/src/main/helm/exec-helm/exec-env.injectable.ts index 3a72d0c17c..29864427a4 100644 --- a/packages/core/src/main/helm/exec-helm/exec-env.injectable.ts +++ b/packages/core/src/main/helm/exec-helm/exec-env.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import httpsProxyConfigurationInjectable from "../../../common/user-store/https-proxy.injectable"; +import httpsProxyConfigurationInjectable from "../../../features/user-preferences/common/https-proxy.injectable"; const execHelmEnvInjectable = getInjectable({ id: "exec-helm-env", diff --git a/packages/core/src/main/kubectl/create-kubectl.injectable.ts b/packages/core/src/main/kubectl/create-kubectl.injectable.ts index 5d7b19162c..84e5fee601 100644 --- a/packages/core/src/main/kubectl/create-kubectl.injectable.ts +++ b/packages/core/src/main/kubectl/create-kubectl.injectable.ts @@ -6,7 +6,6 @@ import { getInjectable } from "@ogre-tools/injectable"; import type { KubectlDependencies } from "./kubectl"; import { Kubectl } from "./kubectl"; import directoryForKubectlBinariesInjectable from "../../common/app-paths/directory-for-kubectl-binaries/directory-for-kubectl-binaries.injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; import kubectlDownloadingNormalizedArchInjectable from "./normalized-arch.injectable"; import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable"; import kubectlBinaryNameInjectable from "./binary-name.injectable"; @@ -20,6 +19,7 @@ import getBasenameOfPathInjectable from "../../common/path/get-basename.injectab import loggerInjectable from "../../common/logger.injectable"; import execFileInjectable from "../../common/fs/exec-file.injectable"; import unlinkInjectable from "../../common/fs/unlink.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; export type CreateKubectl = (version: string) => Kubectl; @@ -28,7 +28,7 @@ const createKubectlInjectable = getInjectable({ instantiate: (di): CreateKubectl => { const dependencies: KubectlDependencies = { - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), directoryForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable), normalizedDownloadArch: di.inject(kubectlDownloadingNormalizedArchInjectable), normalizedDownloadPlatform: di.inject(normalizedPlatformInjectable), diff --git a/packages/core/src/main/kubectl/kubectl.ts b/packages/core/src/main/kubectl/kubectl.ts index ca0fac16e2..631e08b833 100644 --- a/packages/core/src/main/kubectl/kubectl.ts +++ b/packages/core/src/main/kubectl/kubectl.ts @@ -7,7 +7,6 @@ import fs from "fs"; import { ensureDir, pathExists } from "fs-extra"; import * as lockFile from "proper-lockfile"; import { SemVer, coerce } from "semver"; -import { defaultPackageMirror, packageMirrors } from "../../common/user-store/preferences-helpers"; import got from "got/dist/source"; import { promisify } from "util"; import stream from "stream"; @@ -20,6 +19,7 @@ import type { Logger } from "../../common/logger"; import type { ExecFile } from "../../common/fs/exec-file.injectable"; import { hasTypedProperty, isObject, isString, json } from "@k8slens/utilities"; import type { Unlink } from "../../common/fs/unlink.injectable"; +import { packageMirrors, defaultPackageMirror } from "../../features/user-preferences/common/preferences-helpers"; const initScriptVersionString = "# lens-initscript v3"; @@ -30,7 +30,7 @@ export interface KubectlDependencies { readonly kubectlBinaryName: string; readonly bundledKubectlBinaryPath: string; readonly baseBundeledBinariesDirectory: string; - readonly userStore: { + readonly state: { readonly kubectlBinariesPath?: string; readonly downloadBinariesPath?: string; readonly downloadKubectlBinaries: boolean; @@ -91,12 +91,12 @@ export class Kubectl { } public getPathFromPreferences() { - return this.dependencies.userStore.kubectlBinariesPath || this.getBundledPath(); + return this.dependencies.state.kubectlBinariesPath || this.getBundledPath(); } protected getDownloadDir() { - if (this.dependencies.userStore.downloadBinariesPath) { - return this.dependencies.joinPaths(this.dependencies.userStore.downloadBinariesPath, "kubectl"); + if (this.dependencies.state.downloadBinariesPath) { + return this.dependencies.joinPaths(this.dependencies.state.downloadBinariesPath, "kubectl"); } return this.dependencies.directoryForKubectlBinaries; @@ -107,7 +107,7 @@ export class Kubectl { return this.getBundledPath(); } - if (this.dependencies.userStore.downloadKubectlBinaries === false) { + if (this.dependencies.state.downloadKubectlBinaries === false) { return this.getPathFromPreferences(); } @@ -231,7 +231,7 @@ export class Kubectl { } public async ensureKubectl(): Promise { - if (this.dependencies.userStore.downloadKubectlBinaries === false) { + if (this.dependencies.state.downloadKubectlBinaries === false) { return true; } @@ -303,7 +303,7 @@ export class Kubectl { protected async writeInitScripts() { const binariesDir = this.dependencies.baseBundeledBinariesDirectory; - const kubectlPath = this.dependencies.userStore.downloadKubectlBinaries + const kubectlPath = this.dependencies.state.downloadKubectlBinaries ? this.dirname : this.dependencies.getDirnameOfPath(this.getPathFromPreferences()); @@ -370,7 +370,7 @@ export class Kubectl { protected getDownloadMirror(): string { // MacOS packages are only available from default - const { url } = packageMirrors.get(this.dependencies.userStore.downloadMirror) + const { url } = packageMirrors.get(this.dependencies.state.downloadMirror) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion ?? packageMirrors.get(defaultPackageMirror)!; diff --git a/packages/core/src/main/shell-session/local-shell-session/local-shell-session.ts b/packages/core/src/main/shell-session/local-shell-session/local-shell-session.ts index 567fc1dca7..b066702266 100644 --- a/packages/core/src/main/shell-session/local-shell-session/local-shell-session.ts +++ b/packages/core/src/main/shell-session/local-shell-session/local-shell-session.ts @@ -3,17 +3,17 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { UserStore } from "../../../common/user-store"; import type { ShellSessionArgs, ShellSessionDependencies } from "../shell-session"; import { ShellSession } from "../shell-session"; import type { ModifyTerminalShellEnv } from "../shell-env-modifier/modify-terminal-shell-env.injectable"; import type { JoinPaths } from "../../../common/path/join-paths.injectable"; import type { GetDirnameOfPath } from "../../../common/path/get-dirname.injectable"; import type { GetBasenameOfPath } from "../../../common/path/get-basename.injectable"; +import type { UserPreferencesState } from "../../../features/user-preferences/common/state.injectable"; export interface LocalShellSessionDependencies extends ShellSessionDependencies { readonly directoryForBinaries: string; - readonly userStore: UserStore; + readonly state: UserPreferencesState; modifyTerminalShellEnv: ModifyTerminalShellEnv; joinPaths: JoinPaths; getDirnameOfPath: GetDirnameOfPath; @@ -50,8 +50,8 @@ export class LocalShellSession extends ShellSession { } protected async getShellArgs(shell: string): Promise { - const pathFromPreferences = this.dependencies.userStore.kubectlBinariesPath || this.kubectl.getBundledPath(); - const kubectlPathDir = this.dependencies.userStore.downloadKubectlBinaries + const pathFromPreferences = this.dependencies.state.kubectlBinariesPath || this.kubectl.getBundledPath(); + const kubectlPathDir = this.dependencies.state.downloadKubectlBinaries ? this.dependencies.directoryContainingKubectl : this.dependencies.getDirnameOfPath(pathFromPreferences); diff --git a/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts b/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts index 4d5d54984a..c7d396b41a 100644 --- a/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts +++ b/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts @@ -12,19 +12,19 @@ import isMacInjectable from "../../../common/vars/is-mac.injectable"; import type { Cluster } from "../../../common/cluster/cluster"; import isWindowsInjectable from "../../../common/vars/is-windows.injectable"; import loggerInjectable from "../../../common/logger.injectable"; -import userStoreInjectable from "../../../common/user-store/user-store.injectable"; import type WebSocket from "ws"; import getDirnameOfPathInjectable from "../../../common/path/get-dirname.injectable"; import joinPathsInjectable from "../../../common/path/join-paths.injectable"; import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable"; import computeShellEnvironmentInjectable from "../../../features/shell-sync/main/compute-shell-environment.injectable"; import spawnPtyInjectable from "../spawn-pty.injectable"; -import userShellSettingInjectable from "../../../common/user-store/shell-setting.injectable"; import appNameInjectable from "../../../common/vars/app-name.injectable"; import buildVersionInjectable from "../../vars/build-version/build-version.injectable"; import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable"; import statInjectable from "../../../common/fs/stat.injectable"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; +import userPreferencesStateInjectable from "../../../features/user-preferences/common/state.injectable"; +import userShellSettingInjectable from "../../../features/user-preferences/common/shell-setting.injectable"; export interface OpenLocalShellSessionArgs { websocket: WebSocket; @@ -44,7 +44,7 @@ const openLocalShellSessionInjectable = getInjectable({ isMac: di.inject(isMacInjectable), isWindows: di.inject(isWindowsInjectable), logger: di.inject(loggerInjectable), - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), userShellSetting: di.inject(userShellSettingInjectable), appName: di.inject(appNameInjectable), buildVersion: di.inject(buildVersionInjectable), diff --git a/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts b/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts index 55ec26d362..d2ce8ffb17 100644 --- a/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts +++ b/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts @@ -14,7 +14,6 @@ import loggerInjectable from "../../../common/logger.injectable"; import createKubeJsonApiForClusterInjectable from "../../../common/k8s-api/create-kube-json-api-for-cluster.injectable"; import computeShellEnvironmentInjectable from "../../../features/shell-sync/main/compute-shell-environment.injectable"; import spawnPtyInjectable from "../spawn-pty.injectable"; -import userShellSettingInjectable from "../../../common/user-store/shell-setting.injectable"; import appNameInjectable from "../../../common/vars/app-name.injectable"; import buildVersionInjectable from "../../vars/build-version/build-version.injectable"; import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable"; @@ -22,6 +21,7 @@ import statInjectable from "../../../common/fs/stat.injectable"; import createKubeApiInjectable from "../../../common/k8s-api/create-kube-api.injectable"; import loadProxyKubeconfigInjectable from "../../cluster/load-proxy-kubeconfig.injectable"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; +import userShellSettingInjectable from "../../../features/user-preferences/common/shell-setting.injectable"; export interface NodeShellSessionArgs { websocket: WebSocket; diff --git a/packages/core/src/main/stores/init-user-store.injectable.ts b/packages/core/src/main/stores/init-user-store.injectable.ts deleted file mode 100644 index b7d1dac33d..0000000000 --- a/packages/core/src/main/stores/init-user-store.injectable.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import userStoreFileNameMigrationInjectable from "../../common/user-store/file-name-migration.injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; -import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; -import initDefaultUpdateChannelInjectable from "../vars/default-update-channel/init.injectable"; - -const initUserStoreInjectable = getInjectable({ - id: "init-user-store", - instantiate: (di) => ({ - run: async () => { - const userStore = di.inject(userStoreInjectable); - const userStoreFileNameMigration = di.inject(userStoreFileNameMigrationInjectable); - - await userStoreFileNameMigration(); - userStore.load(); - }, - runAfter: initDefaultUpdateChannelInjectable, - }), - injectionToken: beforeApplicationIsLoadingInjectionToken, -}); - -export default initUserStoreInjectable; diff --git a/packages/core/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.injectable.tsx b/packages/core/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.injectable.tsx index 6a03466abd..2707f99a3b 100644 --- a/packages/core/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.injectable.tsx +++ b/packages/core/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.injectable.tsx @@ -7,15 +7,15 @@ import { getInjectable } from "@ogre-tools/injectable"; import React from "react"; import execFileInjectable from "../../../../common/fs/exec-file.injectable"; import loggerInjectable from "../../../../common/logger.injectable"; -import { defaultExtensionRegistryUrl } from "../../../../common/user-store/preferences-helpers"; -import userStoreInjectable from "../../../../common/user-store/user-store.injectable"; +import { defaultExtensionRegistryUrl } from "../../../../features/user-preferences/common/preferences-helpers"; +import userPreferencesStateInjectable from "../../../../features/user-preferences/common/state.injectable"; import showErrorNotificationInjectable from "../../notifications/show-error-notification.injectable"; const getBaseRegistryUrlInjectable = getInjectable({ id: "get-base-registry-url", instantiate: (di) => { - const { extensionRegistryUrl } = di.inject(userStoreInjectable); + const { extensionRegistryUrl } = di.inject(userPreferencesStateInjectable); const showErrorNotification = di.inject(showErrorNotificationInjectable); const logger = di.inject(loggerInjectable); const execFile = di.inject(execFileInjectable); diff --git a/packages/core/src/renderer/components/dock/logs/list.tsx b/packages/core/src/renderer/components/dock/logs/list.tsx index 6b3eded365..d0e437e720 100644 --- a/packages/core/src/renderer/components/dock/logs/list.tsx +++ b/packages/core/src/renderer/components/dock/logs/list.tsx @@ -15,7 +15,6 @@ import { disposeOnUnmount, observer } from "mobx-react"; import moment from "moment-timezone"; import type { Align, ListOnScrollProps } from "react-window"; import { SearchStore } from "../../../search-store/search-store"; -import type { UserStore } from "../../../../common/user-store"; import { array, cssNames } from "@k8slens/utilities"; import type { VirtualListRef } from "../../virtual-list"; import { VirtualList } from "../../virtual-list"; @@ -23,8 +22,9 @@ import { ToBottom } from "./to-bottom"; import type { LogTabViewModel } from "../logs/logs-view-model"; import { Spinner } from "../../spinner"; import { withInjectables } from "@ogre-tools/injectable-react"; -import userStoreInjectable from "../../../../common/user-store/user-store.injectable"; import autoBindReact from "auto-bind/react"; +import type { UserPreferencesState } from "../../../../features/user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../features/user-preferences/common/state.injectable"; export interface LogListProps { model: LogTabViewModel; @@ -37,7 +37,7 @@ export interface LogListRef { } interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } @observer @@ -129,7 +129,7 @@ class NonForwardedLogList extends React.Component (`${logTimestamp && moment.tz(logTimestamp, this.props.userStore.localeTimezone).format()}${log}`)); + .map(([logTimestamp, log]) => (`${logTimestamp && moment.tz(logTimestamp, this.props.state.localeTimezone).format()}${log}`)); } /** @@ -283,7 +283,7 @@ class NonForwardedLogList extends React.Component }>(NonForwardedLogList, { getProps: (di, props) => ({ ...props, - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), }), }); diff --git a/packages/core/src/renderer/components/dock/terminal/create-terminal.injectable.ts b/packages/core/src/renderer/components/dock/terminal/create-terminal.injectable.ts index 2ff82e2c17..88e7514855 100644 --- a/packages/core/src/renderer/components/dock/terminal/create-terminal.injectable.ts +++ b/packages/core/src/renderer/components/dock/terminal/create-terminal.injectable.ts @@ -8,13 +8,12 @@ import { Terminal } from "./terminal"; import type { TabId } from "../dock/store"; import type { TerminalApi } from "../../../api/terminal-api"; import terminalSpawningPoolInjectable from "./terminal-spawning-pool.injectable"; -import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable"; -import terminalCopyOnSelectInjectable - from "../../../../common/user-store/terminal-copy-on-select.injectable"; import isMacInjectable from "../../../../common/vars/is-mac.injectable"; import openLinkInBrowserInjectable from "../../../../common/utils/open-link-in-browser.injectable"; import xtermColorThemeInjectable from "../../../themes/terminal-colors.injectable"; import loggerInjectable from "../../../../common/logger.injectable"; +import terminalConfigInjectable from "../../../../features/user-preferences/common/terminal-config.injectable"; +import terminalCopyOnSelectInjectable from "../../../../features/user-preferences/common/terminal-copy-on-select.injectable"; export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal; diff --git a/packages/core/src/renderer/components/dock/terminal/terminal.ts b/packages/core/src/renderer/components/dock/terminal/terminal.ts index 9e307aa7dc..a0c3a5384a 100644 --- a/packages/core/src/renderer/components/dock/terminal/terminal.ts +++ b/packages/core/src/renderer/components/dock/terminal/terminal.ts @@ -14,11 +14,11 @@ import { disposer } from "@k8slens/utilities"; import { once } from "lodash"; import { clipboard } from "electron"; import type { Logger } from "../../../../common/logger"; -import type { TerminalConfig } from "../../../../common/user-store/preferences-helpers"; import assert from "assert"; import { TerminalChannels } from "../../../../common/terminal/channels"; import { LinkProvider } from "xterm-link-provider"; import type { OpenLinkInBrowser } from "../../../../common/utils/open-link-in-browser.injectable"; +import type { TerminalConfig } from "../../../../features/user-preferences/common/preferences-helpers"; export interface TerminalDependencies { readonly spawningPool: HTMLElement; diff --git a/packages/core/src/renderer/components/item-object-list/content.tsx b/packages/core/src/renderer/components/item-object-list/content.tsx index 17b864ed6e..2b11a97570 100644 --- a/packages/core/src/renderer/components/item-object-list/content.tsx +++ b/packages/core/src/renderer/components/item-object-list/content.tsx @@ -25,15 +25,17 @@ import type { LensTheme } from "../../themes/lens-theme"; import { MenuActions } from "../menu/menu-actions"; import { MenuItem } from "../menu"; import { Checkbox } from "../checkbox"; -import type { UserStore } from "../../../common/user-store"; import type { ItemListStore } from "./list-layout"; import { withInjectables } from "@ogre-tools/injectable-react"; -import userStoreInjectable from "../../../common/user-store/user-store.injectable"; import pageFiltersStoreInjectable from "./page-filters/store.injectable"; import type { OpenConfirmDialog } from "../confirm-dialog/open.injectable"; import openConfirmDialogInjectable from "../confirm-dialog/open.injectable"; import activeThemeInjectable from "../../themes/active.injectable"; import autoBindReact from "auto-bind/react"; +import type { ToggleTableColumnVisibility } from "../../../features/user-preferences/common/toggle-table-column-visibility.injectable"; +import toggleTableColumnVisibilityInjectable from "../../../features/user-preferences/common/toggle-table-column-visibility.injectable"; +import type { IsTableColumnHidden } from "../../../features/user-preferences/common/is-table-column-hidden.injectable"; +import isTableColumnHiddenInjectable from "../../../features/user-preferences/common/is-table-column-hidden.injectable"; export interface ItemListLayoutContentProps { getFilters: () => Filter[]; @@ -74,9 +76,10 @@ export interface ItemListLayoutContentProps; - userStore: UserStore; pageFiltersStore: PageFiltersStore; openConfirmDialog: OpenConfirmDialog; + toggleTableColumnVisibility: ToggleTableColumnVisibility; + isTableColumnHidden: IsTableColumnHidden; } @observer @@ -342,7 +345,7 @@ class NonInjectedItemListLayoutContent< showColumn({ id: columnId, showWithColumn }: TableCellProps): boolean { const { tableId, isConfigurable } = this.props; - return !isConfigurable || !tableId || !this.props.userStore.isTableColumnHidden(tableId, columnId, showWithColumn); + return !isConfigurable || !tableId || !this.props.isTableColumnHidden(tableId, columnId, showWithColumn); } renderColumnVisibilityMenu(tableId: string) { @@ -365,7 +368,7 @@ class NonInjectedItemListLayoutContent< `} value={this.showColumn(cellProps)} - onChange={() => this.props.userStore.toggleTableColumnVisibility(tableId, cellProps.id)} + onChange={() => this.props.toggleTableColumnVisibility(tableId, cellProps.id)} /> )) @@ -379,8 +382,9 @@ export const ItemListLayoutContent = withInjectables ({ ...props, activeTheme: di.inject(activeThemeInjectable), - userStore: di.inject(userStoreInjectable), pageFiltersStore: di.inject(pageFiltersStoreInjectable), openConfirmDialog: di.inject(openConfirmDialogInjectable), + toggleTableColumnVisibility: di.inject(toggleTableColumnVisibilityInjectable), + isTableColumnHidden: di.inject(isTableColumnHiddenInjectable), }), }) as (props: ItemListLayoutContentProps) => React.ReactElement; diff --git a/packages/core/src/renderer/components/locale-date/locale-date.tsx b/packages/core/src/renderer/components/locale-date/locale-date.tsx index 28b5f6b05a..4ec558e617 100644 --- a/packages/core/src/renderer/components/locale-date/locale-date.tsx +++ b/packages/core/src/renderer/components/locale-date/locale-date.tsx @@ -6,27 +6,27 @@ import React from "react"; import { observer } from "mobx-react"; import moment from "moment-timezone"; -import type { UserStore } from "../../../common/user-store"; import { withInjectables } from "@ogre-tools/injectable-react"; -import userStoreInjectable from "../../../common/user-store/user-store.injectable"; +import type { UserPreferencesState } from "../../../features/user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../features/user-preferences/common/state.injectable"; export interface LocaleDateProps { date: string; } interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedLocaleDate = observer(({ date, userStore }: LocaleDateProps & Dependencies) => ( +const NonInjectedLocaleDate = observer(({ date, state }: LocaleDateProps & Dependencies) => ( <> - {`${moment.tz(date, userStore.localeTimezone).format()}`} + {`${moment.tz(date, state.localeTimezone).format()}`} )); export const LocaleDate = withInjectables(NonInjectedLocaleDate, { getProps: (di, props) => ({ ...props, - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), }), }); diff --git a/packages/core/src/renderer/components/monaco-editor/monaco-editor.tsx b/packages/core/src/renderer/components/monaco-editor/monaco-editor.tsx index d41ab4157b..7e36639c41 100644 --- a/packages/core/src/renderer/components/monaco-editor/monaco-editor.tsx +++ b/packages/core/src/renderer/components/monaco-editor/monaco-editor.tsx @@ -13,15 +13,15 @@ import type { MonacoTheme } from "./monaco-themes"; import { type MonacoValidator, monacoValidators } from "./monaco-validators"; import { debounce, merge } from "lodash"; import { cssNames, disposer } from "@k8slens/utilities"; -import type { UserStore } from "../../../common/user-store"; import type { LensTheme } from "../../themes/lens-theme"; import { withInjectables } from "@ogre-tools/injectable-react"; -import userStoreInjectable from "../../../common/user-store/user-store.injectable"; import activeThemeInjectable from "../../themes/active.injectable"; import getEditorHeightFromLinesCountInjectable from "./get-editor-height-from-lines-number.injectable"; import type { Logger } from "../../../common/logger"; import loggerInjectable from "../../../common/logger.injectable"; import autoBindReact from "auto-bind/react"; +import type { UserPreferencesState } from "../../../features/user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../features/user-preferences/common/state.injectable"; export type MonacoEditorId = string; @@ -45,7 +45,7 @@ export interface MonacoEditorProps { } interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; activeTheme: IComputedValue; getEditorHeightFromLinesCount: (linesCount: number) => number; logger: Logger; @@ -116,7 +116,7 @@ class NonInjectedMonacoEditor extends React.Component( - React.forwardRef((props, ref) => ), - { - getProps: (di, props) => ({ - ...props, - userStore: di.inject(userStoreInjectable), - activeTheme: di.inject(activeThemeInjectable), - getEditorHeightFromLinesCount: di.inject(getEditorHeightFromLinesCountInjectable), - logger: di.inject(loggerInjectable), - }), - }, -); +const ForwardedRefMonacoEditor = React.forwardRef(( + (props, ref) => +)); + +export const MonacoEditor = withInjectables(ForwardedRefMonacoEditor, { + getProps: (di, props) => ({ + ...props, + state: di.inject(userPreferencesStateInjectable), + activeTheme: di.inject(activeThemeInjectable), + getEditorHeightFromLinesCount: di.inject(getEditorHeightFromLinesCountInjectable), + logger: di.inject(loggerInjectable), + }), +}); diff --git a/packages/core/src/renderer/initializers/add-sync-entries.injectable.tsx b/packages/core/src/renderer/initializers/add-sync-entries.injectable.tsx index 2f9f3ec74e..5d42d0e496 100644 --- a/packages/core/src/renderer/initializers/add-sync-entries.injectable.tsx +++ b/packages/core/src/renderer/initializers/add-sync-entries.injectable.tsx @@ -3,24 +3,24 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; import React from "react"; import navigateToKubernetesPreferencesInjectable from "../../features/preferences/common/navigate-to-kubernetes-preferences.injectable"; import { runInAction } from "mobx"; import showSuccessNotificationInjectable from "../components/notifications/show-success-notification.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; const addSyncEntriesInjectable = getInjectable({ id: "add-sync-entries", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); const navigateToKubernetesPreferences = di.inject(navigateToKubernetesPreferencesInjectable); const showSuccessNotification = di.inject(showSuccessNotificationInjectable); return async (paths: string[]) => { runInAction(() => { for (const path of paths) { - userStore.syncKubeconfigEntries.set(path, {}); + state.syncKubeconfigEntries.set(path, {}); } }); diff --git a/packages/core/src/renderer/stores/init-user-store.injectable.ts b/packages/core/src/renderer/stores/init-user-store.injectable.ts deleted file mode 100644 index af192d9b2e..0000000000 --- a/packages/core/src/renderer/stores/init-user-store.injectable.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; -import { beforeFrameStartsSecondInjectionToken } from "../before-frame-starts/tokens"; -import initDefaultUpdateChannelInjectable from "../vars/default-update-channel/init.injectable"; - -const initUserStoreInjectable = getInjectable({ - id: "init-user-store", - instantiate: (di) => ({ - run: () => { - const userStore = di.inject(userStoreInjectable); - - return userStore.load(); - }, - runAfter: initDefaultUpdateChannelInjectable, - }), - injectionToken: beforeFrameStartsSecondInjectionToken, -}); - -export default initUserStoreInjectable; diff --git a/packages/core/src/renderer/themes/active.injectable.ts b/packages/core/src/renderer/themes/active.injectable.ts index e22aee237b..324bbf8117 100644 --- a/packages/core/src/renderer/themes/active.injectable.ts +++ b/packages/core/src/renderer/themes/active.injectable.ts @@ -5,7 +5,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import assert from "assert"; import { computed } from "mobx"; -import lensColorThemePreferenceInjectable from "../../common/user-store/lens-color-theme.injectable"; +import lensColorThemePreferenceInjectable from "../../features/user-preferences/common/lens-color-theme.injectable"; import { lensThemeDeclarationInjectionToken } from "./declaration"; import defaultLensThemeInjectable from "./default-theme.injectable"; import systemThemeConfigurationInjectable from "./system-theme.injectable"; diff --git a/packages/core/src/renderer/themes/apply-lens-theme.injectable.ts b/packages/core/src/renderer/themes/apply-lens-theme.injectable.ts index 94afd5c531..977c5eb77c 100644 --- a/packages/core/src/renderer/themes/apply-lens-theme.injectable.ts +++ b/packages/core/src/renderer/themes/apply-lens-theme.injectable.ts @@ -4,9 +4,9 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import loggerInjectable from "../../common/logger.injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; import { object } from "@k8slens/utilities"; import type { LensTheme } from "./lens-theme"; +import resetThemeInjectable from "../../features/user-preferences/common/reset-theme.injectable"; export type ApplyLensTheme = (theme: LensTheme) => void; @@ -14,7 +14,7 @@ const applyLensThemeInjectable = getInjectable({ id: "apply-lens-theme", instantiate: (di): ApplyLensTheme => { const logger = di.inject(loggerInjectable); - const userStore = di.inject(userStoreInjectable); + const resetTheme = di.inject(resetThemeInjectable); return (theme) => { try { @@ -28,7 +28,7 @@ const applyLensThemeInjectable = getInjectable({ document.body.classList.toggle("theme-light", theme.type === "light"); } catch (error) { logger.error("[THEME]: Failed to apply active theme", error); - userStore.resetTheme(); + resetTheme(); } }; }, diff --git a/packages/core/src/renderer/themes/setup-apply-active-theme.injectable.ts b/packages/core/src/renderer/themes/setup-apply-active-theme.injectable.ts index c71dd5baa7..f658093f8e 100644 --- a/packages/core/src/renderer/themes/setup-apply-active-theme.injectable.ts +++ b/packages/core/src/renderer/themes/setup-apply-active-theme.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import { reaction } from "mobx"; import initializeSystemThemeTypeInjectable from "../../features/theme/system-type/renderer/initialize.injectable"; import { beforeFrameStartsSecondInjectionToken } from "../before-frame-starts/tokens"; -import initUserStoreInjectable from "../stores/init-user-store.injectable"; +import initUserStoreInjectable from "../../features/user-preferences/renderer/load-storage.injectable"; import activeThemeInjectable from "./active.injectable"; import applyLensThemeInjectable from "./apply-lens-theme.injectable"; diff --git a/packages/core/src/renderer/themes/terminal-colors.injectable.ts b/packages/core/src/renderer/themes/terminal-colors.injectable.ts index c7010b08b6..7b83d7b16c 100644 --- a/packages/core/src/renderer/themes/terminal-colors.injectable.ts +++ b/packages/core/src/renderer/themes/terminal-colors.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import terminalThemePreferenceInjectable from "../../common/user-store/terminal-theme.injectable"; +import terminalThemePreferenceInjectable from "../../features/user-preferences/common/terminal-theme.injectable"; import activeThemeInjectable from "./active.injectable"; import lensThemesInjectable from "./themes.injectable"; diff --git a/packages/core/src/test-utils/override-fs-with-fakes.ts b/packages/core/src/test-utils/override-fs-with-fakes.ts index 87f8dd583a..5eaeb90ba7 100644 --- a/packages/core/src/test-utils/override-fs-with-fakes.ts +++ b/packages/core/src/test-utils/override-fs-with-fakes.ts @@ -63,6 +63,7 @@ export const getOverrideFsWithFakes = () => { createReadStream: root.createReadStream as any, stat: root.promises.stat as any, unlink: root.promises.unlink, + rename: root.promises.rename, })); }; };