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:
1 parent
a6d1b7a3a4
commit
f95ed19a7d
24 files changed
+369
-385
No files matched your search
+33
-5
@@ -2524,12 +2524,40 @@ exports[`remove helm repository from list of active repositories in preferences
|
||||
Synced Items
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="loading-spinner"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="Spinner singleColor"
|
||||
/>
|
||||
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
|
||||
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>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
+13
-12
@@ -8,12 +8,13 @@ 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 { defaultLocaleTimezone } from "../../../../../../common/user-store/preferences-helpers";
|
||||
import moment from "moment-timezone";
|
||||
import { observer } from "mobx-react";
|
||||
import currentTimezoneInjectable from "../../../../../../common/user-store/current-timezone.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
userStore: UserStore;
|
||||
currentTimezone: string;
|
||||
}
|
||||
|
||||
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">
|
||||
<SubTitle title="Locale Timezone" />
|
||||
<Select
|
||||
id="timezone-input"
|
||||
options={timezoneOptions}
|
||||
value={userStore.localeTimezone}
|
||||
onChange={value => userStore.localeTimezone = value?.value ?? defaultLocaleTimezone}
|
||||
onChange={value => userStore.localeTimezone = value?.value ?? currentTimezone}
|
||||
themeName="lens"
|
||||
/>
|
||||
</section>
|
||||
|
||||
));
|
||||
|
||||
export const Timezone = withInjectables<Dependencies>(
|
||||
NonInjectedTimezone,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
export const Timezone = withInjectables<Dependencies>(NonInjectedTimezone, {
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
currentTimezone: di.inject(currentTimezoneInjectable),
|
||||
}),
|
||||
});
|
||||
+20
@@ -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;
|
||||
+46
@@ -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;
|
||||
+28
-57
@@ -3,12 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import fse from "fs-extra";
|
||||
import { computed, makeObservable, observable, reaction } from "mobx";
|
||||
import { action, 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 { KubeconfigSyncEntry, KubeconfigSyncValue, UserStore } from "../../../../../../common/user-store";
|
||||
import type { UserStore } from "../../../../../../common/user-store";
|
||||
import { iter, tuple } from "../../../../../../renderer/utils";
|
||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||
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 loggerInjectable from "../../../../../../common/logger.injectable";
|
||||
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 {
|
||||
type: "file" | "folder" | "unknown";
|
||||
}
|
||||
|
||||
interface Entry extends Value {
|
||||
interface Entry extends SyncKind {
|
||||
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 {
|
||||
userStore: UserStore;
|
||||
isWindows: boolean;
|
||||
logger: Logger;
|
||||
discoverAllKubeconfigSyncKinds: DiscoverAllKubeconfigSyncKinds;
|
||||
discoverKubeconfigSyncKind: DiscoverKubeconfigSyncKind;
|
||||
}
|
||||
|
||||
@observer
|
||||
class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
||||
syncs = observable.map<string, Value>();
|
||||
readonly syncs = observable.map<string, SyncKind>();
|
||||
@observable loaded = false;
|
||||
|
||||
constructor(props: Dependencies) {
|
||||
@@ -79,7 +48,7 @@ class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
||||
const mapEntries = await Promise.all(
|
||||
iter.map(
|
||||
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, [
|
||||
reaction(
|
||||
() => Array.from(this.syncs.entries(), ([filePath, { data }]) => tuple.from(filePath, data)),
|
||||
() => Array.from(this.syncs.entries(), ([filePath, kind]) => tuple.from(filePath, kind)),
|
||||
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[]) => {
|
||||
this.syncs.merge(await getAllEntries(filePaths, this.props.logger));
|
||||
this.syncs.merge(await this.props.discoverAllKubeconfigSyncKinds(filePaths));
|
||||
};
|
||||
|
||||
getIconName(entry: Entry) {
|
||||
switch (entry.info.type) {
|
||||
switch (entry.type) {
|
||||
case "file":
|
||||
return "description";
|
||||
case "folder":
|
||||
@@ -206,14 +179,12 @@ class NonInjectedKubeconfigSync extends React.Component<Dependencies> {
|
||||
}
|
||||
}
|
||||
|
||||
export const KubeconfigSync = withInjectables<Dependencies>(
|
||||
NonInjectedKubeconfigSync,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
isWindows: di.inject(isWindowsInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
export const KubeconfigSync = withInjectables<Dependencies>(NonInjectedKubeconfigSync, {
|
||||
getProps: (di) => ({
|
||||
userStore: di.inject(userStoreInjectable),
|
||||
isWindows: di.inject(isWindowsInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
discoverAllKubeconfigSyncKinds: di.inject(discoverAllKubeconfigSyncKindsInjectable),
|
||||
discoverKubeconfigSyncKind: di.inject(discoverKubeconfigSyncKindInjectable),
|
||||
}),
|
||||
});
|
||||
Reference in new issue
Block a user