mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix test flakiness by removing side effects from userStore preferences
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
a6d1b7a3a4
commit
f95ed19a7d
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import type { Stats } from "fs";
|
import type { Stats } from "fs";
|
||||||
import fsInjectable from "../fs.injectable";
|
import fsInjectable from "./fs.injectable";
|
||||||
|
|
||||||
export type Stat = (path: string) => Promise<Stats>;
|
export type Stat = (path: string) => Promise<Stats>;
|
||||||
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
import statInjectable from "./stat.injectable";
|
|
||||||
import { getGlobalOverride } from "../../test-utils/get-global-override";
|
|
||||||
|
|
||||||
export default getGlobalOverride(statInjectable, () => () => {
|
|
||||||
throw new Error("Tried to call stat without explicit override");
|
|
||||||
});
|
|
||||||
@ -7,7 +7,7 @@ import type { AsyncResult } from "../utils/async-result";
|
|||||||
import { isErrnoException } from "../utils";
|
import { isErrnoException } from "../utils";
|
||||||
import type { Stats } from "fs-extra";
|
import type { Stats } from "fs-extra";
|
||||||
import { lowerFirst } from "lodash/fp";
|
import { lowerFirst } from "lodash/fp";
|
||||||
import statInjectable from "./stat/stat.injectable";
|
import statInjectable from "./stat.injectable";
|
||||||
|
|
||||||
export type ValidateDirectory = (path: string) => Promise<AsyncResult<undefined>>;
|
export type ValidateDirectory = (path: string) => Promise<AsyncResult<undefined>>;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getGlobalOverride } from "../test-utils/get-global-override";
|
||||||
|
import currentTimezoneInjectable from "./current-timezone.injectable";
|
||||||
|
|
||||||
|
export default getGlobalOverride(currentTimezoneInjectable, () => "Etc/GMT");
|
||||||
14
src/common/user-store/current-timezone.injectable.ts
Normal file
14
src/common/user-store/current-timezone.injectable.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
const currentTimezoneInjectable = getInjectable({
|
||||||
|
id: "current-timezone",
|
||||||
|
instantiate: () => moment.tz.guess(true),
|
||||||
|
causesSideEffects: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default currentTimezoneInjectable;
|
||||||
141
src/common/user-store/preference-descriptors.injectable.ts
Normal file
141
src/common/user-store/preference-descriptors.injectable.ts
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/**
|
||||||
|
* 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 { merge } from "lodash";
|
||||||
|
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 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"]>;
|
||||||
|
|
||||||
|
const userStorePreferenceDescriptorsInjectable = getInjectable({
|
||||||
|
id: "user-store-preference-descriptors",
|
||||||
|
instantiate: (di) => {
|
||||||
|
const currentTimezone = di.inject(currentTimezoneInjectable);
|
||||||
|
const joinPaths = di.inject(joinPathsInjectable);
|
||||||
|
const homeDirectoryPath = di.inject(homeDirectoryPathInjectable);
|
||||||
|
|
||||||
|
const mainKubeFolderPath = joinPaths(homeDirectoryPath, ".kube");
|
||||||
|
|
||||||
|
return ({
|
||||||
|
httpsProxy: getPreferenceDescriptor<string | undefined>({
|
||||||
|
fromStore: val => val,
|
||||||
|
toStore: val => val || undefined,
|
||||||
|
}),
|
||||||
|
shell: getPreferenceDescriptor<string | undefined>({
|
||||||
|
fromStore: val => val,
|
||||||
|
toStore: val => val || undefined,
|
||||||
|
}),
|
||||||
|
colorTheme: getPreferenceDescriptor<string>({
|
||||||
|
fromStore: val => val || defaultThemeId,
|
||||||
|
toStore: val => !val || val === defaultThemeId
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
terminalTheme: getPreferenceDescriptor<string>({
|
||||||
|
fromStore: val => val || "",
|
||||||
|
toStore: val => val || undefined,
|
||||||
|
}),
|
||||||
|
localeTimezone: getPreferenceDescriptor<string>({
|
||||||
|
fromStore: val => val || currentTimezone,
|
||||||
|
toStore: val => !val || val === currentTimezone
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
allowUntrustedCAs: getPreferenceDescriptor<boolean>({
|
||||||
|
fromStore: val => val ?? false,
|
||||||
|
toStore: val => !val
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
allowErrorReporting: getPreferenceDescriptor<boolean>({
|
||||||
|
fromStore: val => val ?? true,
|
||||||
|
toStore: val => val
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
downloadMirror: getPreferenceDescriptor<string>({
|
||||||
|
fromStore: val => !val || !packageMirrors.has(val)
|
||||||
|
? defaultPackageMirror
|
||||||
|
: val,
|
||||||
|
toStore: val => val === defaultPackageMirror
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
downloadKubectlBinaries: getPreferenceDescriptor<boolean>({
|
||||||
|
fromStore: val => val ?? true,
|
||||||
|
toStore: val => val
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
downloadBinariesPath: getPreferenceDescriptor<string | undefined>({
|
||||||
|
fromStore: val => val,
|
||||||
|
toStore: val => val || undefined,
|
||||||
|
}),
|
||||||
|
kubectlBinariesPath: getPreferenceDescriptor<string | undefined>({
|
||||||
|
fromStore: val => val,
|
||||||
|
toStore: val => val || undefined,
|
||||||
|
}),
|
||||||
|
openAtLogin: getPreferenceDescriptor<boolean>({
|
||||||
|
fromStore: val => val ?? false,
|
||||||
|
toStore: val => !val
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
terminalCopyOnSelect: getPreferenceDescriptor<boolean>({
|
||||||
|
fromStore: val => val ?? false,
|
||||||
|
toStore: val => !val
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
hiddenTableColumns: getPreferenceDescriptor<[string, string[]][], Map<string, Set<string>>>({
|
||||||
|
fromStore: (val = []) => new Map(
|
||||||
|
val.map(([tableId, columnIds]) => [tableId, new Set(columnIds)]),
|
||||||
|
),
|
||||||
|
toStore: (val) => {
|
||||||
|
const res: [string, string[]][] = [];
|
||||||
|
|
||||||
|
for (const [table, columns] of val) {
|
||||||
|
if (columns.size) {
|
||||||
|
res.push([table, Array.from(columns)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.length ? res : undefined;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
syncKubeconfigEntries: getPreferenceDescriptor<KubeconfigSyncEntry[], Map<string, KubeconfigSyncValue>>({
|
||||||
|
fromStore: val => new Map(
|
||||||
|
val?.map(({ filePath, ...rest }) => [filePath, rest])
|
||||||
|
?? [[mainKubeFolderPath, {}]],
|
||||||
|
),
|
||||||
|
toStore: val => val.size === 1 && val.has(mainKubeFolderPath)
|
||||||
|
? undefined
|
||||||
|
: Array.from(val, ([filePath, rest]) => ({ filePath, ...rest })),
|
||||||
|
}),
|
||||||
|
editorConfiguration: getPreferenceDescriptor<Partial<EditorConfiguration>, EditorConfiguration>({
|
||||||
|
fromStore: val => merge(defaultEditorConfig, val),
|
||||||
|
toStore: val => val,
|
||||||
|
}),
|
||||||
|
terminalConfig: getPreferenceDescriptor<Partial<TerminalConfig>, TerminalConfig>({
|
||||||
|
fromStore: val => merge(defaultTerminalConfig, val),
|
||||||
|
toStore: val => val,
|
||||||
|
}),
|
||||||
|
extensionRegistryUrl: getPreferenceDescriptor<ExtensionRegistry>({
|
||||||
|
fromStore: val => val ?? {
|
||||||
|
location: defaultExtensionRegistryUrlLocation,
|
||||||
|
},
|
||||||
|
toStore: val => val.location === defaultExtensionRegistryUrlLocation
|
||||||
|
? undefined
|
||||||
|
: val,
|
||||||
|
}),
|
||||||
|
}) as const;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default userStorePreferenceDescriptorsInjectable;
|
||||||
@ -3,14 +3,9 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import moment from "moment-timezone";
|
|
||||||
import path from "path";
|
|
||||||
import os from "os";
|
|
||||||
import type { editor } from "monaco-editor";
|
import type { editor } from "monaco-editor";
|
||||||
import merge from "lodash/merge";
|
import { defaultEditorFontFamily, defaultFontSize, defaultTerminalFontFamily } from "../vars";
|
||||||
import { defaultThemeId, defaultEditorFontFamily, defaultFontSize, defaultTerminalFontFamily } from "../vars";
|
import type { PreferenceDescriptors } from "./preference-descriptors.injectable";
|
||||||
import type { ObservableMap } from "mobx";
|
|
||||||
import { observable } from "mobx";
|
|
||||||
|
|
||||||
export interface KubeconfigSyncEntry extends KubeconfigSyncValue {
|
export interface KubeconfigSyncEntry extends KubeconfigSyncValue {
|
||||||
filePath: string;
|
filePath: string;
|
||||||
@ -54,86 +49,8 @@ export interface PreferenceDescription<T, R = T> {
|
|||||||
toStore(val: R): T | undefined;
|
toStore(val: R): T | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const httpsProxy: PreferenceDescription<string | undefined> = {
|
export const getPreferenceDescriptor = <T, R = T>(desc: PreferenceDescription<T, R>) => desc;
|
||||||
fromStore(val) {
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
return val || undefined;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const shell: PreferenceDescription<string | undefined> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
return val || undefined;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const colorTheme: PreferenceDescription<string> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val || defaultThemeId;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (!val || val === defaultThemeId) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const terminalTheme: PreferenceDescription<string> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val || "";
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
return val || undefined;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const defaultLocaleTimezone = "UTC";
|
|
||||||
|
|
||||||
const localeTimezone: PreferenceDescription<string> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val || moment.tz.guess(true) || defaultLocaleTimezone;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (!val || val === moment.tz.guess(true) || val === defaultLocaleTimezone) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const allowUntrustedCAs: PreferenceDescription<boolean> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val ?? false;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (!val) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const allowErrorReporting: PreferenceDescription<boolean> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val ?? true;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (val === true) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface DownloadMirror {
|
export interface DownloadMirror {
|
||||||
url: string;
|
url: string;
|
||||||
@ -157,142 +74,6 @@ export const packageMirrors = new Map<string, DownloadMirror>([
|
|||||||
}],
|
}],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const downloadMirror: PreferenceDescription<string> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return !val || !packageMirrors.has(val)
|
|
||||||
? defaultPackageMirror
|
|
||||||
: val;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (!val || val === defaultPackageMirror) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadKubectlBinaries: PreferenceDescription<boolean> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val ?? true;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (val === true) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadBinariesPath: PreferenceDescription<string | undefined> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (!val) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const kubectlBinariesPath: PreferenceDescription<string | undefined> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (!val) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const openAtLogin: PreferenceDescription<boolean> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val ?? false;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (!val) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const terminalCopyOnSelect: PreferenceDescription<boolean> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return val ?? false;
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (!val) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const hiddenTableColumns: PreferenceDescription<[string, string[]][], Map<string, Set<string>>> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return new Map(
|
|
||||||
(val ?? []).map(([tableId, columnIds]) => [tableId, new Set(columnIds)]),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
const res: [string, string[]][] = [];
|
|
||||||
|
|
||||||
for (const [table, columns] of val) {
|
|
||||||
if (columns.size) {
|
|
||||||
res.push([table, Array.from(columns)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.length ? res : undefined;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mainKubeFolder = path.join(os.homedir(), ".kube");
|
|
||||||
|
|
||||||
const syncKubeconfigEntries: PreferenceDescription<KubeconfigSyncEntry[], ObservableMap<string, KubeconfigSyncValue>> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return observable.map(
|
|
||||||
val
|
|
||||||
?.map(({ filePath, ...rest }) => [filePath, rest])
|
|
||||||
?? [[mainKubeFolder, {}]],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (val.size === 1 && val.has(mainKubeFolder)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.from(val, ([filePath, rest]) => ({ filePath, ...rest }));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const editorConfiguration: PreferenceDescription<Partial<EditorConfiguration> | undefined, EditorConfiguration> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return merge(defaultEditorConfig, val);
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const terminalConfig: PreferenceDescription<TerminalConfig, TerminalConfig> = {
|
|
||||||
fromStore(val) {
|
|
||||||
return merge(defaultTerminalConfig, val);
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ExtensionRegistryLocation = "default" | "npmrc" | "custom";
|
export type ExtensionRegistryLocation = "default" | "npmrc" | "custom";
|
||||||
|
|
||||||
export type ExtensionRegistry = {
|
export type ExtensionRegistry = {
|
||||||
@ -306,49 +87,13 @@ export type ExtensionRegistry = {
|
|||||||
export const defaultExtensionRegistryUrlLocation = "default";
|
export const defaultExtensionRegistryUrlLocation = "default";
|
||||||
export const defaultExtensionRegistryUrl = "https://registry.npmjs.org";
|
export const defaultExtensionRegistryUrl = "https://registry.npmjs.org";
|
||||||
|
|
||||||
const extensionRegistryUrl: PreferenceDescription<ExtensionRegistry> = {
|
type PreferencesModelType<field extends keyof PreferenceDescriptors> = PreferenceDescriptors[field] extends PreferenceDescription<infer T, any> ? T : never;
|
||||||
fromStore(val) {
|
type UserStoreModelType<field extends keyof PreferenceDescriptors> = PreferenceDescriptors[field] extends PreferenceDescription<any, infer T> ? T : never;
|
||||||
return val ?? {
|
|
||||||
location: defaultExtensionRegistryUrlLocation,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
toStore(val) {
|
|
||||||
if (val.location === defaultExtensionRegistryUrlLocation) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
type PreferencesModelType<field extends keyof typeof DESCRIPTORS> = typeof DESCRIPTORS[field] extends PreferenceDescription<infer T, any> ? T : never;
|
|
||||||
type UserStoreModelType<field extends keyof typeof DESCRIPTORS> = typeof DESCRIPTORS[field] extends PreferenceDescription<any, infer T> ? T : never;
|
|
||||||
|
|
||||||
export type UserStoreFlatModel = {
|
export type UserStoreFlatModel = {
|
||||||
[field in keyof typeof DESCRIPTORS]: UserStoreModelType<field>;
|
[field in keyof PreferenceDescriptors]: UserStoreModelType<field>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserPreferencesModel = {
|
export type UserPreferencesModel = {
|
||||||
[field in keyof typeof DESCRIPTORS]: PreferencesModelType<field>;
|
[field in keyof PreferenceDescriptors]: PreferencesModelType<field>;
|
||||||
} & { updateChannel: string };
|
} & { updateChannel: string };
|
||||||
|
|
||||||
export const DESCRIPTORS = {
|
|
||||||
httpsProxy,
|
|
||||||
shell,
|
|
||||||
colorTheme,
|
|
||||||
terminalTheme,
|
|
||||||
localeTimezone,
|
|
||||||
allowUntrustedCAs,
|
|
||||||
allowErrorReporting,
|
|
||||||
downloadMirror,
|
|
||||||
downloadKubectlBinaries,
|
|
||||||
downloadBinariesPath,
|
|
||||||
kubectlBinariesPath,
|
|
||||||
openAtLogin,
|
|
||||||
hiddenTableColumns,
|
|
||||||
syncKubeconfigEntries,
|
|
||||||
editorConfiguration,
|
|
||||||
terminalCopyOnSelect,
|
|
||||||
terminalConfig,
|
|
||||||
extensionRegistryUrl,
|
|
||||||
};
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-s
|
|||||||
import { persistStateToConfigInjectionToken } from "../base-store/save-to-file";
|
import { persistStateToConfigInjectionToken } from "../base-store/save-to-file";
|
||||||
import getBasenameOfPathInjectable from "../path/get-basename.injectable";
|
import getBasenameOfPathInjectable from "../path/get-basename.injectable";
|
||||||
import { enlistMessageChannelListenerInjectionToken } from "../utils/channel/enlist-message-channel-listener-injection-token";
|
import { enlistMessageChannelListenerInjectionToken } from "../utils/channel/enlist-message-channel-listener-injection-token";
|
||||||
|
import userStorePreferenceDescriptorsInjectable from "./preference-descriptors.injectable";
|
||||||
|
|
||||||
const userStoreInjectable = getInjectable({
|
const userStoreInjectable = getInjectable({
|
||||||
id: "user-store",
|
id: "user-store",
|
||||||
@ -34,6 +35,7 @@ const userStoreInjectable = getInjectable({
|
|||||||
persistStateToConfig: di.inject(persistStateToConfigInjectionToken),
|
persistStateToConfig: di.inject(persistStateToConfigInjectionToken),
|
||||||
enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken),
|
enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken),
|
||||||
shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken),
|
shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken),
|
||||||
|
preferenceDescriptors: di.inject(userStorePreferenceDescriptorsInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -7,13 +7,13 @@ import { action, observable, makeObservable, isObservableArray, isObservableSet,
|
|||||||
import type { BaseStoreDependencies } from "../base-store/base-store";
|
import type { BaseStoreDependencies } from "../base-store/base-store";
|
||||||
import { BaseStore } from "../base-store/base-store";
|
import { BaseStore } from "../base-store/base-store";
|
||||||
import { getOrInsertSet, toggle, toJS, object } from "../../renderer/utils";
|
import { getOrInsertSet, toggle, toJS, object } from "../../renderer/utils";
|
||||||
import { DESCRIPTORS } from "./preferences-helpers";
|
|
||||||
import type { UserPreferencesModel, StoreType } from "./preferences-helpers";
|
import type { UserPreferencesModel, StoreType } from "./preferences-helpers";
|
||||||
import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable";
|
import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable";
|
||||||
|
|
||||||
// TODO: Remove coupling with Feature
|
// TODO: Remove coupling with Feature
|
||||||
import type { SelectedUpdateChannel } from "../../features/application-update/common/selected-update-channel/selected-update-channel.injectable";
|
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 { ReleaseChannel } from "../../features/application-update/common/update-channels";
|
||||||
|
import type { PreferenceDescriptors } from "./preference-descriptors.injectable";
|
||||||
|
|
||||||
export interface UserStoreModel {
|
export interface UserStoreModel {
|
||||||
preferences: UserPreferencesModel;
|
preferences: UserPreferencesModel;
|
||||||
@ -21,6 +21,7 @@ export interface UserStoreModel {
|
|||||||
|
|
||||||
interface Dependencies extends BaseStoreDependencies {
|
interface Dependencies extends BaseStoreDependencies {
|
||||||
readonly selectedUpdateChannel: SelectedUpdateChannel;
|
readonly selectedUpdateChannel: SelectedUpdateChannel;
|
||||||
|
readonly preferenceDescriptors: PreferenceDescriptors;
|
||||||
emitAppEvent: EmitAppEvent;
|
emitAppEvent: EmitAppEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,45 +44,45 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
|||||||
*/
|
*/
|
||||||
@observable newContexts = observable.set<string>();
|
@observable newContexts = observable.set<string>();
|
||||||
|
|
||||||
@observable allowErrorReporting!: StoreType<typeof DESCRIPTORS["allowErrorReporting"]>;
|
@observable allowErrorReporting!: StoreType<PreferenceDescriptors["allowErrorReporting"]>;
|
||||||
@observable allowUntrustedCAs!: StoreType<typeof DESCRIPTORS["allowUntrustedCAs"]>;
|
@observable allowUntrustedCAs!: StoreType<PreferenceDescriptors["allowUntrustedCAs"]>;
|
||||||
@observable colorTheme!: StoreType<typeof DESCRIPTORS["colorTheme"]>;
|
@observable colorTheme!: StoreType<PreferenceDescriptors["colorTheme"]>;
|
||||||
@observable terminalTheme!: StoreType<typeof DESCRIPTORS["terminalTheme"]>;
|
@observable terminalTheme!: StoreType<PreferenceDescriptors["terminalTheme"]>;
|
||||||
@observable localeTimezone!: StoreType<typeof DESCRIPTORS["localeTimezone"]>;
|
@observable localeTimezone!: StoreType<PreferenceDescriptors["localeTimezone"]>;
|
||||||
@observable downloadMirror!: StoreType<typeof DESCRIPTORS["downloadMirror"]>;
|
@observable downloadMirror!: StoreType<PreferenceDescriptors["downloadMirror"]>;
|
||||||
@observable httpsProxy!: StoreType<typeof DESCRIPTORS["httpsProxy"]>;
|
@observable httpsProxy!: StoreType<PreferenceDescriptors["httpsProxy"]>;
|
||||||
@observable shell!: StoreType<typeof DESCRIPTORS["shell"]>;
|
@observable shell!: StoreType<PreferenceDescriptors["shell"]>;
|
||||||
@observable downloadBinariesPath!: StoreType<typeof DESCRIPTORS["downloadBinariesPath"]>;
|
@observable downloadBinariesPath!: StoreType<PreferenceDescriptors["downloadBinariesPath"]>;
|
||||||
@observable kubectlBinariesPath!: StoreType<typeof DESCRIPTORS["kubectlBinariesPath"]>;
|
@observable kubectlBinariesPath!: StoreType<PreferenceDescriptors["kubectlBinariesPath"]>;
|
||||||
@observable terminalCopyOnSelect!: StoreType<typeof DESCRIPTORS["terminalCopyOnSelect"]>;
|
@observable terminalCopyOnSelect!: StoreType<PreferenceDescriptors["terminalCopyOnSelect"]>;
|
||||||
@observable terminalConfig!: StoreType<typeof DESCRIPTORS["terminalConfig"]>;
|
@observable terminalConfig!: StoreType<PreferenceDescriptors["terminalConfig"]>;
|
||||||
@observable extensionRegistryUrl!: StoreType<typeof DESCRIPTORS["extensionRegistryUrl"]>;
|
@observable extensionRegistryUrl!: StoreType<PreferenceDescriptors["extensionRegistryUrl"]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download kubectl binaries matching cluster version
|
* Download kubectl binaries matching cluster version
|
||||||
*/
|
*/
|
||||||
@observable downloadKubectlBinaries!: StoreType<typeof DESCRIPTORS["downloadKubectlBinaries"]>;
|
@observable downloadKubectlBinaries!: StoreType<PreferenceDescriptors["downloadKubectlBinaries"]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the application should open itself at login.
|
* Whether the application should open itself at login.
|
||||||
*/
|
*/
|
||||||
@observable openAtLogin!: StoreType<typeof DESCRIPTORS["openAtLogin"]>;
|
@observable openAtLogin!: StoreType<PreferenceDescriptors["openAtLogin"]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The column IDs under each configurable table ID that have been configured
|
* The column IDs under each configurable table ID that have been configured
|
||||||
* to not be shown
|
* to not be shown
|
||||||
*/
|
*/
|
||||||
@observable hiddenTableColumns!: StoreType<typeof DESCRIPTORS["hiddenTableColumns"]>;
|
@observable hiddenTableColumns!: StoreType<PreferenceDescriptors["hiddenTableColumns"]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Monaco editor configs
|
* Monaco editor configs
|
||||||
*/
|
*/
|
||||||
@observable editorConfiguration!: StoreType<typeof DESCRIPTORS["editorConfiguration"]>;
|
@observable editorConfiguration!: StoreType<PreferenceDescriptors["editorConfiguration"]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of file/folder paths to be synced
|
* The set of file/folder paths to be synced
|
||||||
*/
|
*/
|
||||||
@observable syncKubeconfigEntries!: StoreType<typeof DESCRIPTORS["syncKubeconfigEntries"]>;
|
@observable syncKubeconfigEntries!: StoreType<PreferenceDescriptors["syncKubeconfigEntries"]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a column (by ID) for a table (by ID) is configured to be hidden
|
* Checks if a column (by ID) for a table (by ID) is configured to be hidden
|
||||||
@ -112,14 +113,14 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
resetTheme() {
|
resetTheme() {
|
||||||
this.colorTheme = DESCRIPTORS.colorTheme.fromStore(undefined);
|
this.colorTheme = this.dependencies.preferenceDescriptors.colorTheme.fromStore(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
protected fromStore({ preferences }: Partial<UserStoreModel> = {}) {
|
protected fromStore({ preferences }: Partial<UserStoreModel> = {}) {
|
||||||
this.dependencies.logger.debug("UserStore.fromStore()", { preferences });
|
this.dependencies.logger.debug("UserStore.fromStore()", { preferences });
|
||||||
|
|
||||||
for (const [key, { fromStore }] of object.entries(DESCRIPTORS)) {
|
for (const [key, { fromStore }] of object.entries(this.dependencies.preferenceDescriptors)) {
|
||||||
const curVal = this[key];
|
const curVal = this[key];
|
||||||
const newVal = fromStore((preferences)?.[key] as never) as never;
|
const newVal = fromStore((preferences)?.[key] as never) as never;
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
|
|||||||
|
|
||||||
toJSON(): UserStoreModel {
|
toJSON(): UserStoreModel {
|
||||||
const preferences = object.fromEntries(
|
const preferences = object.fromEntries(
|
||||||
object.entries(DESCRIPTORS)
|
object.entries(this.dependencies.preferenceDescriptors)
|
||||||
.map(([key, { toStore }]) => [key, toStore(this[key] as never)]),
|
.map(([key, { toStore }]) => [key, toStore(this[key] as never)]),
|
||||||
) as UserPreferencesModel;
|
) as UserPreferencesModel;
|
||||||
|
|
||||||
|
|||||||
@ -2524,12 +2524,40 @@ exports[`remove helm repository from list of active repositories in preferences
|
|||||||
Synced Items
|
Synced Items
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<div
|
<div
|
||||||
class="loading-spinner"
|
class="item flex gaps align-center justify-space-between mt-3"
|
||||||
>
|
>
|
||||||
|
<i
|
||||||
|
class="Icon material focusable"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="icon"
|
||||||
|
data-icon-name="folder"
|
||||||
|
>
|
||||||
|
folder
|
||||||
|
</span>
|
||||||
|
</i>
|
||||||
<div
|
<div
|
||||||
class="Spinner singleColor"
|
class="flex-grow break-all"
|
||||||
/>
|
>
|
||||||
|
/some-home-dir/.kube
|
||||||
|
</div>
|
||||||
|
<i
|
||||||
|
class="Icon material interactive focusable"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="icon"
|
||||||
|
data-icon-name="delete"
|
||||||
|
>
|
||||||
|
delete
|
||||||
|
</span>
|
||||||
|
</i>
|
||||||
|
<div>
|
||||||
|
Remove
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -8,12 +8,13 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
|||||||
import type { UserStore } from "../../../../../../common/user-store";
|
import type { UserStore } from "../../../../../../common/user-store";
|
||||||
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
|
||||||
import { Select } from "../../../../../../renderer/components/select";
|
import { Select } from "../../../../../../renderer/components/select";
|
||||||
import { defaultLocaleTimezone } from "../../../../../../common/user-store/preferences-helpers";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
|
import currentTimezoneInjectable from "../../../../../../common/user-store/current-timezone.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
userStore: UserStore;
|
userStore: UserStore;
|
||||||
|
currentTimezone: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const timezoneOptions = moment.tz.names()
|
const timezoneOptions = moment.tz.names()
|
||||||
@ -23,26 +24,26 @@ const timezoneOptions = moment.tz.names()
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
const NonInjectedTimezone = observer(({ userStore }: Dependencies) => (
|
const NonInjectedTimezone = observer(({
|
||||||
|
userStore,
|
||||||
|
currentTimezone,
|
||||||
|
}: Dependencies) => (
|
||||||
<section id="locale">
|
<section id="locale">
|
||||||
<SubTitle title="Locale Timezone" />
|
<SubTitle title="Locale Timezone" />
|
||||||
<Select
|
<Select
|
||||||
id="timezone-input"
|
id="timezone-input"
|
||||||
options={timezoneOptions}
|
options={timezoneOptions}
|
||||||
value={userStore.localeTimezone}
|
value={userStore.localeTimezone}
|
||||||
onChange={value => userStore.localeTimezone = value?.value ?? defaultLocaleTimezone}
|
onChange={value => userStore.localeTimezone = value?.value ?? currentTimezone}
|
||||||
themeName="lens"
|
themeName="lens"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
));
|
));
|
||||||
|
|
||||||
export const Timezone = withInjectables<Dependencies>(
|
export const Timezone = withInjectables<Dependencies>(NonInjectedTimezone, {
|
||||||
NonInjectedTimezone,
|
|
||||||
|
|
||||||
{
|
|
||||||
getProps: (di) => ({
|
getProps: (di) => ({
|
||||||
userStore: di.inject(userStoreInjectable),
|
userStore: di.inject(userStoreInjectable),
|
||||||
|
currentTimezone: di.inject(currentTimezoneInjectable),
|
||||||
}),
|
}),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* 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 type { SyncKind } from "./discover-sync-kind.injectable";
|
||||||
|
import discoverKubeconfigSyncKindInjectable from "./discover-sync-kind.injectable";
|
||||||
|
|
||||||
|
export type DiscoverAllKubeconfigSyncKinds = (filePaths: string[]) => Promise<[string, SyncKind][]>;
|
||||||
|
|
||||||
|
const discoverAllKubeconfigSyncKindsInjectable = getInjectable({
|
||||||
|
id: "discover-all-kubeconfig-sync-kinds",
|
||||||
|
instantiate: (di): DiscoverAllKubeconfigSyncKinds => {
|
||||||
|
const discoverKubeconfigSyncKind = di.inject(discoverKubeconfigSyncKindInjectable);
|
||||||
|
|
||||||
|
return filePaths => Promise.all(filePaths.map(discoverKubeconfigSyncKind));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default discoverAllKubeconfigSyncKindsInjectable;
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* 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 statInjectable from "../../../../../../common/fs/stat.injectable";
|
||||||
|
import loggerInjectable from "../../../../../../common/logger.injectable";
|
||||||
|
|
||||||
|
export interface SyncKind {
|
||||||
|
type: "file" | "folder" | "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DiscoverKubeconfigSyncKind = (path: string) => Promise<[string, SyncKind]>;
|
||||||
|
|
||||||
|
const discoverKubeconfigSyncKindInjectable = getInjectable({
|
||||||
|
id: "discover-kubeconfig-sync-kind",
|
||||||
|
instantiate: (di): DiscoverKubeconfigSyncKind => {
|
||||||
|
const stat = di.inject(statInjectable);
|
||||||
|
const logger = di.inject(loggerInjectable);
|
||||||
|
|
||||||
|
return async (path) => {
|
||||||
|
try {
|
||||||
|
// stat follows the stat(2) linux syscall spec, namely it follows symlinks
|
||||||
|
const stats = await stat(path);
|
||||||
|
|
||||||
|
if (stats.isFile()) {
|
||||||
|
return [path, { type: "file" }];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
return [path, { type: "folder" }];
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.warn("[KUBECONFIG-SYNCS]: unknown stat entry", { stats });
|
||||||
|
|
||||||
|
return [path, { type: "unknown" }];
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn(`[KUBECONFIG-SYNCS]: failed to stat entry: ${error}`, { error });
|
||||||
|
|
||||||
|
return [path, { type: "unknown" }];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default discoverKubeconfigSyncKindInjectable;
|
||||||
@ -3,12 +3,11 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import fse from "fs-extra";
|
import { action, computed, makeObservable, observable, reaction } from "mobx";
|
||||||
import { computed, makeObservable, observable, reaction } from "mobx";
|
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Notice } from "../../../../../../renderer/components/+extensions/notice";
|
import { Notice } from "../../../../../../renderer/components/+extensions/notice";
|
||||||
import type { KubeconfigSyncEntry, KubeconfigSyncValue, UserStore } from "../../../../../../common/user-store";
|
import type { UserStore } from "../../../../../../common/user-store";
|
||||||
import { iter, tuple } from "../../../../../../renderer/utils";
|
import { iter, tuple } from "../../../../../../renderer/utils";
|
||||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||||
import { PathPicker } from "../../../../../../renderer/components/path-picker/path-picker";
|
import { PathPicker } from "../../../../../../renderer/components/path-picker/path-picker";
|
||||||
@ -18,56 +17,26 @@ import userStoreInjectable from "../../../../../../common/user-store/user-store.
|
|||||||
import isWindowsInjectable from "../../../../../../common/vars/is-windows.injectable";
|
import isWindowsInjectable from "../../../../../../common/vars/is-windows.injectable";
|
||||||
import loggerInjectable from "../../../../../../common/logger.injectable";
|
import loggerInjectable from "../../../../../../common/logger.injectable";
|
||||||
import type { Logger } from "../../../../../../common/logger";
|
import type { Logger } from "../../../../../../common/logger";
|
||||||
|
import type { DiscoverAllKubeconfigSyncKinds } from "./discover-all-sync-kinds.injectable";
|
||||||
|
import type { DiscoverKubeconfigSyncKind, SyncKind } from "./discover-sync-kind.injectable";
|
||||||
|
import discoverKubeconfigSyncKindInjectable from "./discover-sync-kind.injectable";
|
||||||
|
import discoverAllKubeconfigSyncKindsInjectable from "./discover-all-sync-kinds.injectable";
|
||||||
|
|
||||||
interface SyncInfo {
|
interface Entry extends SyncKind {
|
||||||
type: "file" | "folder" | "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Entry extends Value {
|
|
||||||
filePath: string;
|
filePath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Value {
|
|
||||||
data: KubeconfigSyncValue;
|
|
||||||
info: SyncInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getMapEntry({ filePath, ...data }: KubeconfigSyncEntry, logger: Logger): Promise<[string, Value]> {
|
|
||||||
try {
|
|
||||||
// stat follows the stat(2) linux syscall spec, namely it follows symlinks
|
|
||||||
const stats = await fse.stat(filePath);
|
|
||||||
|
|
||||||
if (stats.isFile()) {
|
|
||||||
return [filePath, { info: { type: "file" }, data }];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stats.isDirectory()) {
|
|
||||||
return [filePath, { info: { type: "folder" }, data }];
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.warn("[KubeconfigSyncs]: unknown stat entry", { stats });
|
|
||||||
|
|
||||||
return [filePath, { info: { type: "unknown" }, data }];
|
|
||||||
} catch (error) {
|
|
||||||
logger.warn(`[KubeconfigSyncs]: failed to stat entry: ${error}`, { error });
|
|
||||||
|
|
||||||
return [filePath, { info: { type: "unknown" }, data }];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAllEntries(filePaths: string[], logger: Logger): Promise<[string, Value][]> {
|
|
||||||
return Promise.all(filePaths.map(filePath => getMapEntry({ filePath }, logger)));
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
userStore: UserStore;
|
userStore: UserStore;
|
||||||
isWindows: boolean;
|
isWindows: boolean;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
|
discoverAllKubeconfigSyncKinds: DiscoverAllKubeconfigSyncKinds;
|
||||||
|
discoverKubeconfigSyncKind: DiscoverKubeconfigSyncKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
||||||
syncs = observable.map<string, Value>();
|
readonly syncs = observable.map<string, SyncKind>();
|
||||||
@observable loaded = false;
|
@observable loaded = false;
|
||||||
|
|
||||||
constructor(props: Dependencies) {
|
constructor(props: Dependencies) {
|
||||||
@ -79,7 +48,7 @@ class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
|||||||
const mapEntries = await Promise.all(
|
const mapEntries = await Promise.all(
|
||||||
iter.map(
|
iter.map(
|
||||||
this.props.userStore.syncKubeconfigEntries,
|
this.props.userStore.syncKubeconfigEntries,
|
||||||
([filePath, ...value]) => getMapEntry({ filePath, ...value }, this.props.logger),
|
([filePath]) => this.props.discoverKubeconfigSyncKind(filePath),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -88,9 +57,13 @@ class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
|||||||
|
|
||||||
disposeOnUnmount(this, [
|
disposeOnUnmount(this, [
|
||||||
reaction(
|
reaction(
|
||||||
() => Array.from(this.syncs.entries(), ([filePath, { data }]) => tuple.from(filePath, data)),
|
() => Array.from(this.syncs.entries(), ([filePath, kind]) => tuple.from(filePath, kind)),
|
||||||
syncs => {
|
syncs => {
|
||||||
this.props.userStore.syncKubeconfigEntries.replace(syncs);
|
action(() => {
|
||||||
|
for (const [path] of syncs) {
|
||||||
|
this.props.userStore.syncKubeconfigEntries.set(path, {});
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
@ -105,11 +78,11 @@ class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onPick = async (filePaths: string[]) => {
|
onPick = async (filePaths: string[]) => {
|
||||||
this.syncs.merge(await getAllEntries(filePaths, this.props.logger));
|
this.syncs.merge(await this.props.discoverAllKubeconfigSyncKinds(filePaths));
|
||||||
};
|
};
|
||||||
|
|
||||||
getIconName(entry: Entry) {
|
getIconName(entry: Entry) {
|
||||||
switch (entry.info.type) {
|
switch (entry.type) {
|
||||||
case "file":
|
case "file":
|
||||||
return "description";
|
return "description";
|
||||||
case "folder":
|
case "folder":
|
||||||
@ -206,14 +179,12 @@ class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const KubeconfigSync = withInjectables<Dependencies>(
|
export const KubeconfigSync = withInjectables<Dependencies>(NonInjectedKubeconfigSync, {
|
||||||
NonInjectedKubeconfigSync,
|
|
||||||
|
|
||||||
{
|
|
||||||
getProps: (di) => ({
|
getProps: (di) => ({
|
||||||
userStore: di.inject(userStoreInjectable),
|
userStore: di.inject(userStoreInjectable),
|
||||||
isWindows: di.inject(isWindowsInjectable),
|
isWindows: di.inject(isWindowsInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
|
discoverAllKubeconfigSyncKinds: di.inject(discoverAllKubeconfigSyncKindsInjectable),
|
||||||
|
discoverKubeconfigSyncKind: di.inject(discoverKubeconfigSyncKindInjectable),
|
||||||
}),
|
}),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|||||||
@ -22,9 +22,9 @@ import kubeconfigSyncsInjectable from "../../../common/user-store/kubeconfig-syn
|
|||||||
import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable";
|
import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable";
|
||||||
import type { DiContainer } from "@ogre-tools/injectable";
|
import type { DiContainer } from "@ogre-tools/injectable";
|
||||||
import type { AsyncFnMock } from "@async-fn/jest";
|
import type { AsyncFnMock } from "@async-fn/jest";
|
||||||
import type { Stat } from "../../../common/fs/stat/stat.injectable";
|
import type { Stat } from "../../../common/fs/stat.injectable";
|
||||||
import asyncFn from "@async-fn/jest";
|
import asyncFn from "@async-fn/jest";
|
||||||
import statInjectable from "../../../common/fs/stat/stat.injectable";
|
import statInjectable from "../../../common/fs/stat.injectable";
|
||||||
import type { Watcher } from "../../../common/fs/watch/watch.injectable";
|
import type { Watcher } from "../../../common/fs/watch/watch.injectable";
|
||||||
import watchInjectable from "../../../common/fs/watch/watch.injectable";
|
import watchInjectable from "../../../common/fs/watch/watch.injectable";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import path from "path";
|
|||||||
import { inspect } from "util";
|
import { inspect } from "util";
|
||||||
import type { CatalogEntity } from "../../../common/catalog";
|
import type { CatalogEntity } from "../../../common/catalog";
|
||||||
import type { Cluster } from "../../../common/cluster/cluster";
|
import type { Cluster } from "../../../common/cluster/cluster";
|
||||||
import statInjectable from "../../../common/fs/stat/stat.injectable";
|
import statInjectable from "../../../common/fs/stat.injectable";
|
||||||
import type { Watcher } from "../../../common/fs/watch/watch.injectable";
|
import type { Watcher } from "../../../common/fs/watch/watch.injectable";
|
||||||
import watchInjectable from "../../../common/fs/watch/watch.injectable";
|
import watchInjectable from "../../../common/fs/watch/watch.injectable";
|
||||||
import type { Disposer } from "../../../common/utils";
|
import type { Disposer } from "../../../common/utils";
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import helmChartManagerCacheInjectable from "./helm-chart-manager-cache.injectab
|
|||||||
import loggerInjectable from "../../common/logger.injectable";
|
import loggerInjectable from "../../common/logger.injectable";
|
||||||
import execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
import execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||||
import readFileInjectable from "../../common/fs/read-file.injectable";
|
import readFileInjectable from "../../common/fs/read-file.injectable";
|
||||||
import statInjectable from "../../common/fs/stat/stat.injectable";
|
import statInjectable from "../../common/fs/stat.injectable";
|
||||||
|
|
||||||
const helmChartManagerInjectable = getInjectable({
|
const helmChartManagerInjectable = getInjectable({
|
||||||
id: "helm-chart-manager",
|
id: "helm-chart-manager",
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import type { Logger } from "../../common/logger";
|
|||||||
import type { RepoHelmChartList } from "../../common/k8s-api/endpoints/helm-charts.api/request-charts.injectable";
|
import type { RepoHelmChartList } from "../../common/k8s-api/endpoints/helm-charts.api/request-charts.injectable";
|
||||||
import type { ExecHelm } from "./exec-helm/exec-helm.injectable";
|
import type { ExecHelm } from "./exec-helm/exec-helm.injectable";
|
||||||
import type { ReadFile } from "../../common/fs/read-file.injectable";
|
import type { ReadFile } from "../../common/fs/read-file.injectable";
|
||||||
import type { Stat } from "../../common/fs/stat/stat.injectable";
|
import type { Stat } from "../../common/fs/stat.injectable";
|
||||||
|
|
||||||
export interface HelmCacheFile {
|
export interface HelmCacheFile {
|
||||||
apiVersion: string;
|
apiVersion: string;
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import userShellSettingInjectable from "../../../common/user-store/shell-setting
|
|||||||
import appNameInjectable from "../../../common/vars/app-name.injectable";
|
import appNameInjectable from "../../../common/vars/app-name.injectable";
|
||||||
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
|
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
|
||||||
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||||
import statInjectable from "../../../common/fs/stat/stat.injectable";
|
import statInjectable from "../../../common/fs/stat.injectable";
|
||||||
|
|
||||||
export interface OpenLocalShellSessionArgs {
|
export interface OpenLocalShellSessionArgs {
|
||||||
websocket: WebSocket;
|
websocket: WebSocket;
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import userShellSettingInjectable from "../../../common/user-store/shell-setting
|
|||||||
import appNameInjectable from "../../../common/vars/app-name.injectable";
|
import appNameInjectable from "../../../common/vars/app-name.injectable";
|
||||||
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
|
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
|
||||||
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||||
import statInjectable from "../../../common/fs/stat/stat.injectable";
|
import statInjectable from "../../../common/fs/stat.injectable";
|
||||||
|
|
||||||
export interface NodeShellSessionArgs {
|
export interface NodeShellSessionArgs {
|
||||||
websocket: WebSocket;
|
websocket: WebSocket;
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import type { ComputeShellEnvironment } from "../../features/shell-sync/main/com
|
|||||||
import type { SpawnPty } from "./spawn-pty.injectable";
|
import type { SpawnPty } from "./spawn-pty.injectable";
|
||||||
import type { InitializableState } from "../../common/initializable-state/create";
|
import type { InitializableState } from "../../common/initializable-state/create";
|
||||||
import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable";
|
import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable";
|
||||||
import type { Stat } from "../../common/fs/stat/stat.injectable";
|
import type { Stat } from "../../common/fs/stat.injectable";
|
||||||
import type { IComputedValue } from "mobx";
|
import type { IComputedValue } from "mobx";
|
||||||
|
|
||||||
export class ShellOpenError extends Error {
|
export class ShellOpenError extends Error {
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
|||||||
import type { DiRender } from "../../test-utils/renderFor";
|
import type { DiRender } from "../../test-utils/renderFor";
|
||||||
import { renderFor } from "../../test-utils/renderFor";
|
import { renderFor } from "../../test-utils/renderFor";
|
||||||
import showErrorNotificationInjectable from "../../notifications/show-error-notification.injectable";
|
import showErrorNotificationInjectable from "../../notifications/show-error-notification.injectable";
|
||||||
import statInjectable from "../../../../common/fs/stat/stat.injectable";
|
import statInjectable from "../../../../common/fs/stat.injectable";
|
||||||
|
|
||||||
describe("ClusterLocalTerminalSettings", () => {
|
describe("ClusterLocalTerminalSettings", () => {
|
||||||
let render: DiRender;
|
let render: DiRender;
|
||||||
|
|||||||
@ -69,6 +69,9 @@ import { getCompositePaths } from "../../../common/utils/composite/get-composite
|
|||||||
import { discoverFor } from "./discovery-of-html-elements";
|
import { discoverFor } from "./discovery-of-html-elements";
|
||||||
import { findComposite } from "../../../common/utils/composite/find-composite/find-composite";
|
import { findComposite } from "../../../common/utils/composite/find-composite/find-composite";
|
||||||
import shouldStartHiddenInjectable from "../../../main/electron-app/features/should-start-hidden.injectable";
|
import shouldStartHiddenInjectable from "../../../main/electron-app/features/should-start-hidden.injectable";
|
||||||
|
import fsInjectable from "../../../common/fs/fs.injectable";
|
||||||
|
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||||
|
import homeDirectoryPathInjectable from "../../../common/os/home-directory-path.injectable";
|
||||||
|
|
||||||
type Callback = (di: DiContainer) => void | Promise<void>;
|
type Callback = (di: DiContainer) => void | Promise<void>;
|
||||||
|
|
||||||
@ -179,6 +182,15 @@ export const getApplicationBuilder = () => {
|
|||||||
|
|
||||||
overrideFsWithFakes(mainDi);
|
overrideFsWithFakes(mainDi);
|
||||||
|
|
||||||
|
// Set up ~/.kube as existing as a folder
|
||||||
|
{
|
||||||
|
const { ensureDirSync } = mainDi.inject(fsInjectable);
|
||||||
|
const joinPaths = mainDi.inject(joinPathsInjectable);
|
||||||
|
const homeDirectoryPath = mainDi.inject(homeDirectoryPathInjectable);
|
||||||
|
|
||||||
|
ensureDirSync(joinPaths(homeDirectoryPath, ".kube"));
|
||||||
|
}
|
||||||
|
|
||||||
let environment = environments.application;
|
let environment = environments.application;
|
||||||
|
|
||||||
mainDi.override(mainExtensionsInjectable, (di) => {
|
mainDi.override(mainExtensionsInjectable, (di) => {
|
||||||
|
|||||||
@ -2,13 +2,13 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getAllEntries } from "../../features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync";
|
|
||||||
import { Notifications } from "../components/notifications";
|
import { Notifications } from "../components/notifications";
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
import userStoreInjectable from "../../common/user-store/user-store.injectable";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import navigateToKubernetesPreferencesInjectable from "../../features/preferences/common/navigate-to-kubernetes-preferences.injectable";
|
import navigateToKubernetesPreferencesInjectable from "../../features/preferences/common/navigate-to-kubernetes-preferences.injectable";
|
||||||
import loggerInjectable from "../../common/logger.injectable";
|
import discoverAllKubeconfigSyncKindsInjectable from "../../features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/discover-all-sync-kinds.injectable";
|
||||||
|
import { action } from "mobx";
|
||||||
|
|
||||||
const addSyncEntriesInjectable = getInjectable({
|
const addSyncEntriesInjectable = getInjectable({
|
||||||
id: "add-sync-entries",
|
id: "add-sync-entries",
|
||||||
@ -16,12 +16,16 @@ const addSyncEntriesInjectable = getInjectable({
|
|||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const userStore = di.inject(userStoreInjectable);
|
const userStore = di.inject(userStoreInjectable);
|
||||||
const navigateToKubernetesPreferences = di.inject(navigateToKubernetesPreferencesInjectable);
|
const navigateToKubernetesPreferences = di.inject(navigateToKubernetesPreferencesInjectable);
|
||||||
const logger = di.inject(loggerInjectable);
|
const discoverAllKubeconfigSyncKinds = di.inject(discoverAllKubeconfigSyncKindsInjectable);
|
||||||
|
|
||||||
return async (filePaths: string[]) => {
|
return async (filePaths: string[]) => {
|
||||||
userStore.syncKubeconfigEntries.merge(
|
const kinds = await discoverAllKubeconfigSyncKinds(filePaths);
|
||||||
await getAllEntries(filePaths, logger),
|
|
||||||
);
|
action(() => {
|
||||||
|
for (const [path] of kinds) {
|
||||||
|
userStore.syncKubeconfigEntries.set(path, {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Notifications.ok((
|
Notifications.ok((
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user