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

Fully split apart the user preferences storage

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-03-17 14:17:41 -04:00
parent 037c62d426
commit 4055732d41
86 changed files with 720 additions and 806 deletions

View File

@ -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");
});
});
});

View File

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

View File

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

View File

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

View File

@ -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",

View File

@ -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 () => {});

View File

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

View File

@ -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<MigrationDeclaration>({
id: "user-store-migration-token",
});

View File

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

View File

@ -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<Record<string, unknown>>;
emitAppEvent: EmitAppEvent;
createPersistentStorage: CreatePersistentStorage;
}
export class UserStore {
private readonly store: PersistentStorage;
constructor(protected readonly dependencies: Dependencies) {
this.store = this.dependencies.createPersistentStorage<UserStoreModel>({
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<PreferenceDescriptors["allowErrorReporting"]>;
@observable allowUntrustedCAs!: StoreType<PreferenceDescriptors["allowUntrustedCAs"]>;
@observable colorTheme!: StoreType<PreferenceDescriptors["colorTheme"]>;
@observable terminalTheme!: StoreType<PreferenceDescriptors["terminalTheme"]>;
@observable localeTimezone!: StoreType<PreferenceDescriptors["localeTimezone"]>;
@observable downloadMirror!: StoreType<PreferenceDescriptors["downloadMirror"]>;
@observable httpsProxy!: StoreType<PreferenceDescriptors["httpsProxy"]>;
@observable shell!: StoreType<PreferenceDescriptors["shell"]>;
@observable downloadBinariesPath!: StoreType<PreferenceDescriptors["downloadBinariesPath"]>;
@observable kubectlBinariesPath!: StoreType<PreferenceDescriptors["kubectlBinariesPath"]>;
@observable terminalCopyOnSelect!: StoreType<PreferenceDescriptors["terminalCopyOnSelect"]>;
@observable terminalConfig!: StoreType<PreferenceDescriptors["terminalConfig"]>;
@observable extensionRegistryUrl!: StoreType<PreferenceDescriptors["extensionRegistryUrl"]>;
/**
* Download kubectl binaries matching cluster version
*/
@observable downloadKubectlBinaries!: StoreType<PreferenceDescriptors["downloadKubectlBinaries"]>;
/**
* Whether the application should open itself at login.
*/
@observable openAtLogin!: StoreType<PreferenceDescriptors["openAtLogin"]>;
/**
* The column IDs under each configurable table ID that have been configured
* to not be shown
*/
@observable hiddenTableColumns!: StoreType<PreferenceDescriptors["hiddenTableColumns"]>;
/**
* Monaco editor configs
*/
@observable editorConfiguration!: StoreType<PreferenceDescriptors["editorConfiguration"]>;
/**
* The set of file/folder paths to be synced
*/
@observable syncKubeconfigEntries!: StoreType<PreferenceDescriptors["syncKubeconfigEntries"]>;
/**
* 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();
}
}

View File

@ -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 = {

View File

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

View File

@ -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({

View File

@ -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 (
<section id="extensionRegistryUrl">
@ -42,14 +42,14 @@ const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencie
<Select
id="extension-install-registry-input"
options={extensionInstallRegistryOptions}
value={userStore.extensionRegistryUrl.location}
value={state.extensionRegistryUrl.location}
onChange={(value) =>
runInAction(() => {
userStore.extensionRegistryUrl.location =
state.extensionRegistryUrl.location =
value?.value ?? defaultExtensionRegistryUrlLocation;
if (userStore.extensionRegistryUrl.location === "custom") {
userStore.extensionRegistryUrl.customUrl = "";
if (state.extensionRegistryUrl.location === "custom") {
state.extensionRegistryUrl.customUrl = "";
}
})
}
@ -69,20 +69,16 @@ const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencie
validators={isUrl}
value={customUrl}
onChange={setCustomUrl}
onBlur={() => (userStore.extensionRegistryUrl.customUrl = customUrl)}
onBlur={() => (state.extensionRegistryUrl.customUrl = customUrl)}
placeholder="Custom Extension Registry URL..."
disabled={userStore.extensionRegistryUrl.location !== "custom"}
disabled={state.extensionRegistryUrl.location !== "custom"}
/>
</section>
);
});
export const ExtensionInstallRegistry = withInjectables<Dependencies>(
NonInjectedExtensionInstallRegistry,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const ExtensionInstallRegistry = withInjectables<Dependencies>(NonInjectedExtensionInstallRegistry, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -5,33 +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 { Switch } from "../../../../../../renderer/components/switch";
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 NonInjectedStartUp = observer(({ userStore }: Dependencies) => (
const NonInjectedStartUp = observer(({ state }: Dependencies) => (
<section id="other">
<SubTitle title="Start-up" />
<Switch
checked={userStore.openAtLogin}
onChange={() => (userStore.openAtLogin = !userStore.openAtLogin)}
checked={state.openAtLogin}
onChange={() => (state.openAtLogin = !state.openAtLogin)}
>
Automatically start Lens on login
</Switch>
</section>
));
export const StartUp = withInjectables<Dependencies>(
NonInjectedStartUp,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const StartUp = withInjectables<Dependencies>(NonInjectedStartUp, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -7,26 +7,26 @@ import { SubTitle } from "../../../../../../renderer/components/layout/sub-title
import { Select } from "../../../../../../renderer/components/select";
import { withInjectables } from "@ogre-tools/injectable-react";
import { observer } from "mobx-react";
import type { UserStore } from "../../../../../../common/user-store";
import type { LensTheme } from "../../../../../../renderer/themes/lens-theme";
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
import defaultLensThemeInjectable from "../../../../../../renderer/themes/default-theme.injectable";
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;
defaultTheme: LensTheme;
themes: LensTheme[];
}
const NonInjectedTheme = observer(({
userStore,
state,
themes,
defaultTheme,
}: Dependencies) => {
const themeOptions = [
{
value: "system", // TODO: replace with a sentinal value that isn't string (and serialize it differently)
value: "system", // TODO: replace with a sentinel value that isn't string (and serialize it differently)
label: "Sync with computer",
},
...themes.map(theme => ({
@ -41,9 +41,9 @@ const NonInjectedTheme = observer(({
<Select
id="theme-input"
options={themeOptions}
value={userStore.colorTheme}
value={state.colorTheme}
onChange={(value) =>
(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<Dependencies>(NonInjectedTheme, {
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
state: di.inject(userPreferencesStateInjectable),
defaultTheme: di.inject(defaultLensThemeInjectable),
themes: di.injectMany(lensThemeDeclarationInjectionToken),
}),

View File

@ -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) => (
<section id="locale">
@ -33,17 +32,16 @@ const NonInjectedTimezone = observer(({
<Select
id="timezone-input"
options={timezoneOptions}
value={userStore.localeTimezone}
onChange={value => userStore.localeTimezone = value?.value ?? currentTimezone}
value={state.localeTimezone}
onChange={value => state.localeTimezone = value?.value ?? currentTimezone}
themeName="lens"
/>
</section>
));
export const Timezone = withInjectables<Dependencies>(NonInjectedTimezone, {
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
state: di.inject(userPreferencesStateInjectable),
currentTimezone: di.inject(currentTimezoneInjectable),
}),
});

View File

@ -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 } 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 NonInjectedEditorFontFamily = observer(({ userStore: { editorConfiguration }}: Dependencies) => (
const NonInjectedEditorFontFamily = observer(({ state: { editorConfiguration }}: Dependencies) => (
<section>
<SubTitle title="Font family" />
<Input
@ -26,12 +26,8 @@ const NonInjectedEditorFontFamily = observer(({ userStore: { editorConfiguration
</section>
));
export const EditorFontFamily = withInjectables<Dependencies>(
NonInjectedEditorFontFamily,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const EditorFontFamily = withInjectables<Dependencies>(NonInjectedEditorFontFamily, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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) => (
<section>
<SubTitle title="Font size" />
<Input
@ -28,12 +28,8 @@ const NonInjectedEditorFontSize = observer(({ userStore: { editorConfiguration }
</section>
));
export const EditorFontSize = withInjectables<Dependencies>(
NonInjectedEditorFontSize,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const EditorFontSize = withInjectables<Dependencies>(NonInjectedEditorFontSize, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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) => (
<section>
<SubTitle title="Line numbers"/>
<Select
@ -37,15 +37,10 @@ const NonInjectedLineNumbers = observer(({ userStore: { editorConfiguration }}:
themeName="lens"
/>
</section>
));
export const LineNumbers = withInjectables<Dependencies>(
NonInjectedLineNumbers,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const LineNumbers = withInjectables<Dependencies>(NonInjectedLineNumbers, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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 { Switch } from "../../../../../../renderer/components/switch";
import { SubHeader } from "../../../../../../renderer/components/layout/sub-header";
import { Select } from "../../../../../../renderer/components/select";
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 minimapPositionOptions = (["left", "right"] as const)
@ -23,7 +23,7 @@ const minimapPositionOptions = (["left", "right"] as const)
}));
const NonInjectedMinimap = observer(({ userStore: { editorConfiguration }}: Dependencies) => (
const NonInjectedMinimap = observer(({ state: { editorConfiguration }}: Dependencies) => (
<section>
<SubTitle title="Minimap"/>
@ -50,12 +50,8 @@ const NonInjectedMinimap = observer(({ userStore: { editorConfiguration }}: Depe
</section>
));
export const Minimap = withInjectables<Dependencies>(
NonInjectedMinimap,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const Minimap = withInjectables<Dependencies>(NonInjectedMinimap, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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 NonInjectedTabSize = observer(({ userStore: { editorConfiguration }}: Dependencies) => (
const NonInjectedTabSize = observer(({ state: { editorConfiguration }}: Dependencies) => (
<section>
<SubTitle title="Tab size" />
<Input
@ -28,12 +28,8 @@ const NonInjectedTabSize = observer(({ userStore: { editorConfiguration }}: Depe
</section>
));
export const TabSize = withInjectables<Dependencies>(
NonInjectedTabSize,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const TabSize = withInjectables<Dependencies>(NonInjectedTabSize, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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<Dependencies> {
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<Dependencies> {
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<Dependencies> {
export const KubeconfigSync = withInjectables<Dependencies>(NonInjectedKubeconfigSync, {
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
state: di.inject(userPreferencesStateInjectable),
isWindows: di.inject(isWindowsInjectable),
logger: di.inject(loggerInjectable),
discoverAllKubeconfigSyncKinds: di.inject(discoverAllKubeconfigSyncKindsInjectable),

View File

@ -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) => (
<section>
<SubTitle title="Kubectl binary download" />
<Switch
checked={userStore.downloadKubectlBinaries}
onChange={() => userStore.downloadKubectlBinaries = !userStore.downloadKubectlBinaries}
checked={state.downloadKubectlBinaries}
onChange={() => state.downloadKubectlBinaries = !state.downloadKubectlBinaries}
>
Download kubectl binaries matching the Kubernetes cluster version
</Switch>
</section>
));
export const KubectlBinaryDownload = withInjectables<Dependencies>(
NonInjectedKubectlBinaryDownload,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const KubectlBinaryDownload = withInjectables<Dependencies>(NonInjectedKubectlBinaryDownload, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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}
/>
<div className="hint">The directory to download binaries into.</div>
</section>
@ -43,13 +43,9 @@ const NonInjectedKubectlDirectoryForBinaries = observer(
},
);
export const KubectlDirectoryForBinaries = withInjectables<Dependencies>(
NonInjectedKubectlDirectoryForBinaries,
{
getProps: (di) => ({
defaultPathForGeneralBinaries: di.inject(directoryForBinariesInjectable),
userStore: di.inject(userStoreInjectable),
}),
},
);
export const KubectlDirectoryForBinaries = withInjectables<Dependencies>(NonInjectedKubectlDirectoryForBinaries, {
getProps: (di) => ({
defaultPathForGeneralBinaries: di.inject(directoryForBinariesInjectable),
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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) => (
<section>
<SubTitle title="Download mirror" />
<Select
id="download-mirror-input"
placeholder="Download mirror for kubectl"
options={downloadMirrorOptions}
value={userStore.downloadMirror}
onChange={option => userStore.downloadMirror = option?.value ?? defaultPackageMirror}
isDisabled={!userStore.downloadKubectlBinaries}
value={state.downloadMirror}
onChange={option => state.downloadMirror = option?.value ?? defaultPackageMirror}
isDisabled={!state.downloadKubectlBinaries}
themeName="lens"
/>
</section>
));
export const KubectlDownloadMirror = withInjectables<Dependencies>(
NonInjectedKubectlDownloadMirror,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const KubectlDownloadMirror = withInjectables<Dependencies>(NonInjectedKubectlDownloadMirror, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -5,50 +5,48 @@
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 directoryForKubectlBinariesInjectable from "../../../../../../../common/app-paths/directory-for-kubectl-binaries/directory-for-kubectl-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;
defaultPathForKubectlBinaries: string;
}
const NonInjectedKubectlPathToBinary = observer(
({ userStore, defaultPathForKubectlBinaries }: Dependencies) => {
const [binariesPath, setBinariesPath] = useState(userStore.kubectlBinariesPath || "");
const pathValidator = binariesPath ? InputValidators.isPath : undefined;
const NonInjectedKubectlPathToBinary = observer(({
state,
defaultPathForKubectlBinaries,
}: Dependencies) => {
const [binariesPath, setBinariesPath] = useState(state.kubectlBinariesPath || "");
const pathValidator = binariesPath ? InputValidators.isPath : undefined;
const save = () => {
userStore.kubectlBinariesPath = binariesPath;
};
const save = () => {
state.kubectlBinariesPath = binariesPath;
};
return (
<section>
<SubTitle title="Path to kubectl binary" />
<Input
theme="round-black"
placeholder={defaultPathForKubectlBinaries}
value={binariesPath}
validators={pathValidator}
onChange={setBinariesPath}
onBlur={save}
disabled={userStore.downloadKubectlBinaries}
/>
</section>
);
},
return (
<section>
<SubTitle title="Path to kubectl binary" />
<Input
theme="round-black"
placeholder={defaultPathForKubectlBinaries}
value={binariesPath}
validators={pathValidator}
onChange={setBinariesPath}
onBlur={save}
disabled={state.downloadKubectlBinaries}
/>
</section>
);
},
);
export const KubectlPathToBinary = withInjectables<Dependencies>(
NonInjectedKubectlPathToBinary,
{
getProps: (di) => ({
defaultPathForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable),
userStore: di.inject(userStoreInjectable),
}),
},
);
export const KubectlPathToBinary = withInjectables<Dependencies>(NonInjectedKubectlPathToBinary, {
getProps: (di) => ({
defaultPathForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable),
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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) => (
<section className="small">
<SubTitle title="Certificate Trust" />
<Switch
checked={userStore.allowUntrustedCAs}
onChange={() =>
(userStore.allowUntrustedCAs = !userStore.allowUntrustedCAs)
}
checked={state.allowUntrustedCAs}
onChange={() => state.allowUntrustedCAs = !state.allowUntrustedCAs}
>
Allow untrusted Certificate Authorities
</Switch>
@ -33,12 +31,8 @@ const NonInjectedAllowUntrustedCertificates = observer(({ userStore }: Dependenc
</section>
));
export const AllowUntrustedCertificates = withInjectables<Dependencies>(
NonInjectedAllowUntrustedCertificates,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const AllowUntrustedCertificates = withInjectables<Dependencies>(NonInjectedAllowUntrustedCertificates, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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 (
<section>
<SubTitle title="HTTP Proxy" />
<Input
theme="round-black"
placeholder="Type HTTP proxy url (example: http://proxy.acme.org:8080)"
value={proxy}
onChange={(v) => setProxy(v)}
onBlur={() => (userStore.httpsProxy = proxy)}
/>
<small className="hint">
Proxy is used only for non-cluster communication.
</small>
</section>
);
},
);
return (
<section>
<SubTitle title="HTTP Proxy" />
<Input
theme="round-black"
placeholder="Type HTTP proxy url (example: http://proxy.acme.org:8080)"
value={proxy}
onChange={(v) => setProxy(v)}
onBlur={() => (state.httpsProxy = proxy)}
/>
<small className="hint">
Proxy is used only for non-cluster communication.
</small>
</section>
);
});
export const HttpProxyUrl = withInjectables<Dependencies>(
NonInjectedHttpProxyUrl,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const HttpProxyUrl = withInjectables<Dependencies>(NonInjectedHttpProxyUrl, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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) => (
<div
id="sentry"
className="small"
@ -23,8 +23,8 @@ const NonInjectedAutomaticErrorReporting = observer(({ userStore }: Dependencies
<SubTitle title="Automatic Error Reporting" />
<Checkbox
label="Allow automatic error reporting"
value={userStore.allowErrorReporting}
onChange={(value) => (userStore.allowErrorReporting = value)}
value={state.allowErrorReporting}
onChange={(value) => (state.allowErrorReporting = value)}
/>
<div className="hint">
<span>
@ -36,12 +36,8 @@ const NonInjectedAutomaticErrorReporting = observer(({ userStore }: Dependencies
</div>
));
export const AutomaticErrorReporting = withInjectables<Dependencies>(
NonInjectedAutomaticErrorReporting,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const AutomaticErrorReporting = withInjectables<Dependencies>(NonInjectedAutomaticErrorReporting, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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) => (
<section id="terminalSelection">
<SubTitle title="Terminal copy & paste" />
<Switch
checked={state.terminalCopyOnSelect}
onChange={() => state.terminalCopyOnSelect = !state.terminalCopyOnSelect}
>
Copy on select and paste on right-click
</Switch>
</section>
));
return (
<section id="terminalSelection">
<SubTitle title="Terminal copy & paste" />
<Switch
checked={userStore.terminalCopyOnSelect}
onChange={() => userStore.terminalCopyOnSelect = !userStore.terminalCopyOnSelect}
>
Copy on select and paste on right-click
</Switch>
</section>
);
},
);
export const CopyPasteFromTerminal = withInjectables<Dependencies>(
NonInjectedCopyPasteFromTerminal,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const CopyPasteFromTerminal = withInjectables<Dependencies>(NonInjectedCopyPasteFromTerminal, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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<SelectOption<string>[]>;
@ -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({
<span
style={{
fontFamily: `${font.name}, var(--font-terminal)`,
fontSize: userStore.terminalConfig.fontSize,
fontSize: state.terminalConfig.fontSize,
}}
>
{font.name}
</span>
),
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;
}),
};
},

View File

@ -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) => (
<section>
<SubTitle title="Font size" />
<Input
theme="round-black"
type="number"
min={10}
max={50}
defaultValue={state.terminalConfig.fontSize.toString()}
onChange={(value) => state.terminalConfig.fontSize = Number(value)} />
</section>
));
return (
<section>
<SubTitle title="Font size" />
<Input
theme="round-black"
type="number"
min={10}
max={50}
defaultValue={userStore.terminalConfig.fontSize.toString()}
onChange={(value) => userStore.terminalConfig.fontSize = Number(value)}
/>
</section>
);
},
);
export const TerminalFontSize = withInjectables<Dependencies>(
NonInjectedTerminalFontSize,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
}),
},
);
export const TerminalFontSize = withInjectables<Dependencies>(NonInjectedTerminalFontSize, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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) => (
<section id="shell">
<SubTitle title="Terminal Shell Path" />
<Input
theme="round-black"
placeholder={defaultShell}
value={state.shell ?? ""}
onChange={(value) => state.shell = value}
/>
</section>
));
return (
<section id="shell">
<SubTitle title="Terminal Shell Path" />
<Input
theme="round-black"
placeholder={defaultShell}
value={userStore.shell ?? ""}
onChange={(value) => userStore.shell = value}
/>
</section>
);
},
);
export const TerminalShellPath = withInjectables<Dependencies>(
NonInjectedTerminalShellPath,
{
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
defaultShell: di.inject(defaultShellInjectable),
}),
},
);
export const TerminalShellPath = withInjectables<Dependencies>(NonInjectedTerminalShellPath, {
getProps: (di) => ({
state: di.inject(userPreferencesStateInjectable),
defaultShell: di.inject(defaultShellInjectable),
}),
});

View File

@ -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 ?? ""}
/>
</section>
);
@ -50,7 +49,7 @@ const NonInjectedTerminalTheme = observer(({
export const TerminalTheme = withInjectables<Dependencies>(NonInjectedTerminalTheme, {
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
state: di.inject(userPreferencesStateInjectable),
themes: di.injectMany(lensThemeDeclarationInjectionToken),
}),
});

View File

@ -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",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { MigrationDeclaration } from "../../../common/persistent-storage/migrations.injectable";
export const userPreferencesMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
id: "user-preferences-migration-token",
});

View File

@ -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<typeof userStorePreferenceDescriptorsInjectable["instantiate"]>;
export type PreferenceDescriptors = ReturnType<typeof userPreferenceDescriptorsInjectable["instantiate"]>;
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;

View File

@ -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>;
[field in keyof PreferenceDescriptors]?: PreferencesModelType<field>;
} & { updateChannel: string };

View File

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

View File

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

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { 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<PreferenceDescriptors[Field]>;
};
const userPreferencesStateInjectable = getInjectable({
id: "user-preferences-state",
instantiate: () => observable.object({} as UserPreferencesState),
});
export default userPreferencesStateInjectable;

View File

@ -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<UserStoreModel>({
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;

View File

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

View File

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

View File

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

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { 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;

View File

@ -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<string, string[]>;
}
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;

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { 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;

View File

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

View File

@ -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",

View File

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

View File

@ -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",

View File

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

View File

@ -7,7 +7,6 @@ import fs from "fs";
import { ensureDir, pathExists } from "fs-extra";
import * as lockFile from "proper-lockfile";
import { SemVer, coerce } from "semver";
import { defaultPackageMirror, packageMirrors } from "../../common/user-store/preferences-helpers";
import got from "got/dist/source";
import { promisify } from "util";
import stream from "stream";
@ -20,6 +19,7 @@ import type { Logger } from "../../common/logger";
import type { ExecFile } from "../../common/fs/exec-file.injectable";
import { hasTypedProperty, isObject, isString, json } from "@k8slens/utilities";
import type { Unlink } from "../../common/fs/unlink.injectable";
import { packageMirrors, defaultPackageMirror } from "../../features/user-preferences/common/preferences-helpers";
const initScriptVersionString = "# lens-initscript v3";
@ -30,7 +30,7 @@ export interface KubectlDependencies {
readonly kubectlBinaryName: string;
readonly bundledKubectlBinaryPath: string;
readonly baseBundeledBinariesDirectory: string;
readonly userStore: {
readonly state: {
readonly kubectlBinariesPath?: string;
readonly downloadBinariesPath?: string;
readonly downloadKubectlBinaries: boolean;
@ -91,12 +91,12 @@ export class Kubectl {
}
public getPathFromPreferences() {
return this.dependencies.userStore.kubectlBinariesPath || this.getBundledPath();
return this.dependencies.state.kubectlBinariesPath || this.getBundledPath();
}
protected getDownloadDir() {
if (this.dependencies.userStore.downloadBinariesPath) {
return this.dependencies.joinPaths(this.dependencies.userStore.downloadBinariesPath, "kubectl");
if (this.dependencies.state.downloadBinariesPath) {
return this.dependencies.joinPaths(this.dependencies.state.downloadBinariesPath, "kubectl");
}
return this.dependencies.directoryForKubectlBinaries;
@ -107,7 +107,7 @@ export class Kubectl {
return this.getBundledPath();
}
if (this.dependencies.userStore.downloadKubectlBinaries === false) {
if (this.dependencies.state.downloadKubectlBinaries === false) {
return this.getPathFromPreferences();
}
@ -231,7 +231,7 @@ export class Kubectl {
}
public async ensureKubectl(): Promise<boolean> {
if (this.dependencies.userStore.downloadKubectlBinaries === false) {
if (this.dependencies.state.downloadKubectlBinaries === false) {
return true;
}
@ -303,7 +303,7 @@ export class Kubectl {
protected async writeInitScripts() {
const binariesDir = this.dependencies.baseBundeledBinariesDirectory;
const kubectlPath = this.dependencies.userStore.downloadKubectlBinaries
const kubectlPath = this.dependencies.state.downloadKubectlBinaries
? this.dirname
: this.dependencies.getDirnameOfPath(this.getPathFromPreferences());
@ -370,7 +370,7 @@ export class Kubectl {
protected getDownloadMirror(): string {
// MacOS packages are only available from default
const { url } = packageMirrors.get(this.dependencies.userStore.downloadMirror)
const { url } = packageMirrors.get(this.dependencies.state.downloadMirror)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
?? packageMirrors.get(defaultPackageMirror)!;

View File

@ -3,17 +3,17 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { UserStore } from "../../../common/user-store";
import type { ShellSessionArgs, ShellSessionDependencies } from "../shell-session";
import { ShellSession } from "../shell-session";
import type { ModifyTerminalShellEnv } from "../shell-env-modifier/modify-terminal-shell-env.injectable";
import type { JoinPaths } from "../../../common/path/join-paths.injectable";
import type { GetDirnameOfPath } from "../../../common/path/get-dirname.injectable";
import type { GetBasenameOfPath } from "../../../common/path/get-basename.injectable";
import type { UserPreferencesState } from "../../../features/user-preferences/common/state.injectable";
export interface LocalShellSessionDependencies extends ShellSessionDependencies {
readonly directoryForBinaries: string;
readonly userStore: UserStore;
readonly state: UserPreferencesState;
modifyTerminalShellEnv: ModifyTerminalShellEnv;
joinPaths: JoinPaths;
getDirnameOfPath: GetDirnameOfPath;
@ -50,8 +50,8 @@ export class LocalShellSession extends ShellSession {
}
protected async getShellArgs(shell: string): Promise<string[]> {
const pathFromPreferences = this.dependencies.userStore.kubectlBinariesPath || this.kubectl.getBundledPath();
const kubectlPathDir = this.dependencies.userStore.downloadKubectlBinaries
const pathFromPreferences = this.dependencies.state.kubectlBinariesPath || this.kubectl.getBundledPath();
const kubectlPathDir = this.dependencies.state.downloadKubectlBinaries
? this.dependencies.directoryContainingKubectl
: this.dependencies.getDirnameOfPath(pathFromPreferences);

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Dependencies & LogListProps &
return this.props.model.timestampSplitLogs
.get()
.map(([logTimestamp, log]) => (`${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<Dependencies & LogListProps &
const InjectedNonForwardedLogList = withInjectables<Dependencies, LogListProps & { innerRef: ForwardedRef<LogListRef> }>(NonForwardedLogList, {
getProps: (di, props) => ({
...props,
userStore: di.inject(userStoreInjectable),
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

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

View File

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

View File

@ -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<Item extends ItemObject, PreLoadStores extends boolean> {
getFilters: () => Filter[];
@ -74,9 +76,10 @@ export interface ItemListLayoutContentProps<Item extends ItemObject, PreLoadStor
interface Dependencies {
activeTheme: IComputedValue<LensTheme>;
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<
<Checkbox
label={cellProps.title ?? `<${cellProps.className}>`}
value={this.showColumn(cellProps)}
onChange={() => this.props.userStore.toggleTableColumnVisibility(tableId, cellProps.id)}
onChange={() => this.props.toggleTableColumnVisibility(tableId, cellProps.id)}
/>
</MenuItem>
))
@ -379,8 +382,9 @@ export const ItemListLayoutContent = withInjectables<Dependencies, ItemListLayou
getProps: (di, props) => ({
...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 <Item extends ItemObject, PreLoadStores extends boolean>(props: ItemListLayoutContentProps<Item, PreLoadStores>) => React.ReactElement;

View File

@ -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<Dependencies, LocaleDateProps>(NonInjectedLocaleDate, {
getProps: (di, props) => ({
...props,
userStore: di.inject(userStoreInjectable),
state: di.inject(userPreferencesStateInjectable),
}),
});

View File

@ -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<LensTheme>;
getEditorHeightFromLinesCount: (linesCount: number) => number;
logger: Logger;
@ -116,7 +116,7 @@ class NonInjectedMonacoEditor extends React.Component<MonacoEditorProps & Depend
@computed get options(): editor.IStandaloneEditorConstructionOptions {
return merge({},
this.props.userStore.editorConfiguration,
this.props.state.editorConfiguration,
this.props.options,
);
}
@ -325,15 +325,16 @@ class NonInjectedMonacoEditor extends React.Component<MonacoEditorProps & Depend
}
}
export const MonacoEditor = withInjectables<Dependencies, MonacoEditorProps, MonacoEditorRef>(
React.forwardRef<MonacoEditorRef, MonacoEditorProps & Dependencies>((props, ref) => <NonInjectedMonacoEditor innerRef={ref} {...props} />),
{
getProps: (di, props) => ({
...props,
userStore: di.inject(userStoreInjectable),
activeTheme: di.inject(activeThemeInjectable),
getEditorHeightFromLinesCount: di.inject(getEditorHeightFromLinesCountInjectable),
logger: di.inject(loggerInjectable),
}),
},
);
const ForwardedRefMonacoEditor = React.forwardRef<MonacoEditorRef, MonacoEditorProps & Dependencies>((
(props, ref) => <NonInjectedMonacoEditor innerRef={ref} {...props} />
));
export const MonacoEditor = withInjectables<Dependencies, MonacoEditorProps, MonacoEditorRef>(ForwardedRefMonacoEditor, {
getProps: (di, props) => ({
...props,
state: di.inject(userPreferencesStateInjectable),
activeTheme: di.inject(activeThemeInjectable),
getEditorHeightFromLinesCount: di.inject(getEditorHeightFromLinesCountInjectable),
logger: di.inject(loggerInjectable),
}),
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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