mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
fix dock-store.test.ts test by overriding createStorage to not touch file system
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
35e49fe6e6
commit
199f142559
@ -7,7 +7,7 @@ import { action, observable, reaction, when, makeObservable } from "mobx";
|
|||||||
import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
|
import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
|
||||||
import type { Cluster, ClusterApi } from "../../../../common/k8s-api/endpoints";
|
import type { Cluster, ClusterApi } from "../../../../common/k8s-api/endpoints";
|
||||||
import { getMetricsByNodeNames, type ClusterMetricData } from "../../../../common/k8s-api/endpoints";
|
import { getMetricsByNodeNames, type ClusterMetricData } from "../../../../common/k8s-api/endpoints";
|
||||||
import type { StorageHelper } from "../../../utils";
|
import type { StorageLayer } from "../../../utils";
|
||||||
import { autoBind } from "../../../utils";
|
import { autoBind } from "../../../utils";
|
||||||
import { type IMetricsReqParams, normalizeMetrics } from "../../../../common/k8s-api/endpoints/metrics.api";
|
import { type IMetricsReqParams, normalizeMetrics } from "../../../../common/k8s-api/endpoints/metrics.api";
|
||||||
import { nodesStore } from "../../+nodes/nodes.store";
|
import { nodesStore } from "../../+nodes/nodes.store";
|
||||||
@ -28,7 +28,7 @@ export interface ClusterOverviewStorageState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
storage: StorageHelper<ClusterOverviewStorageState>;
|
storage: StorageLayer<ClusterOverviewStorageState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClusterOverviewStore extends KubeObjectStore<Cluster, ClusterApi> implements ClusterOverviewStorageState {
|
export class ClusterOverviewStore extends KubeObjectStore<Cluster, ClusterApi> implements ClusterOverviewStorageState {
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import type { IReactionDisposer } from "mobx";
|
import type { IReactionDisposer } from "mobx";
|
||||||
import { action, comparer, computed, makeObservable, reaction } from "mobx";
|
import { action, comparer, computed, makeObservable, reaction } from "mobx";
|
||||||
import type { StorageHelper } from "../../../utils";
|
import type { StorageLayer } from "../../../utils";
|
||||||
import { autoBind, noop, toggle } from "../../../utils";
|
import { autoBind, noop, toggle } from "../../../utils";
|
||||||
import type { KubeObjectStoreLoadingParams } from "../../../../common/k8s-api/kube-object.store";
|
import type { KubeObjectStoreLoadingParams } from "../../../../common/k8s-api/kube-object.store";
|
||||||
import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
|
import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
|
||||||
@ -13,7 +13,7 @@ import type { NamespaceApi } from "../../../../common/k8s-api/endpoints/namespac
|
|||||||
import { Namespace } from "../../../../common/k8s-api/endpoints/namespaces.api";
|
import { Namespace } from "../../../../common/k8s-api/endpoints/namespaces.api";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
storage: StorageHelper<string[] | undefined>;
|
storage: StorageLayer<string[] | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
|
export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
|
||||||
@ -70,7 +70,7 @@ export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
|
|||||||
* @private
|
* @private
|
||||||
* The current value (list of namespaces names) in the storage layer
|
* The current value (list of namespaces names) in the storage layer
|
||||||
*/
|
*/
|
||||||
@computed private get selectedNamespaces(): string[] {
|
@computed private get selectedNamespaces() {
|
||||||
return this.dependencies.storage.get() ?? [];
|
return this.dependencies.storage.get() ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
|
|||||||
/**
|
/**
|
||||||
* The list of selected namespace names (for filtering)
|
* The list of selected namespace names (for filtering)
|
||||||
*/
|
*/
|
||||||
@computed get contextNamespaces(): string[] {
|
@computed get contextNamespaces() {
|
||||||
if (!this.selectedNamespaces.length) {
|
if (!this.selectedNamespaces.length) {
|
||||||
return this.allowedNamespaces; // show all namespaces when nothing selected
|
return this.allowedNamespaces; // show all namespaces when nothing selected
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
import hostedClusterIdInjectable from "../../../../common/cluster-store/hosted-cluster-id.injectable";
|
||||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||||
import type { DockStore, DockTab } from "../dock/store";
|
import type { DockStore, DockTab } from "../dock/store";
|
||||||
import { TabKind } from "../dock/store";
|
import { TabKind } from "../dock/store";
|
||||||
import dockStoreInjectable from "../dock/store.injectable";
|
import dockStoreInjectable from "../dock/store.injectable";
|
||||||
import fse from "fs-extra";
|
|
||||||
|
|
||||||
const initialTabs: DockTab[] = [
|
const initialTabs: DockTab[] = [
|
||||||
{ id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false },
|
{ id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false },
|
||||||
@ -24,20 +23,11 @@ describe("DockStore", () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||||
|
|
||||||
di.override(
|
di.override(hostedClusterIdInjectable, () => "some-cluster-id");
|
||||||
directoryForUserDataInjectable,
|
|
||||||
() => "some-test-suite-specific-directory-for-user-data",
|
|
||||||
);
|
|
||||||
await di.runSetups();
|
await di.runSetups();
|
||||||
|
|
||||||
dockStore = di.inject(dockStoreInjectable);
|
dockStore = di.inject(dockStoreInjectable);
|
||||||
|
|
||||||
await dockStore.whenReady;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
fse.remove("some-test-suite-specific-directory-for-user-data");
|
|
||||||
dockStore.closeAllTabs();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("closes tab and selects one from right", () => {
|
it("closes tab and selects one from right", () => {
|
||||||
|
|||||||
@ -4,8 +4,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, observable, reaction } from "mobx";
|
import { action, observable, reaction } from "mobx";
|
||||||
import type { StorageHelper } from "../../../utils";
|
import type { StorageLayer } from "../../../utils";
|
||||||
import { autoBind, toJS } from "../../../utils";
|
import { autoBind, toJS } from "../../../utils";
|
||||||
|
import type { CreateStorage } from "../../../utils/create-storage/create-storage";
|
||||||
import type { TabId } from "../dock/store";
|
import type { TabId } from "../dock/store";
|
||||||
|
|
||||||
export interface DockTabStoreOptions {
|
export interface DockTabStoreOptions {
|
||||||
@ -16,11 +17,11 @@ export interface DockTabStoreOptions {
|
|||||||
export type DockTabStorageState<T> = Record<TabId, T>;
|
export type DockTabStorageState<T> = Record<TabId, T>;
|
||||||
|
|
||||||
interface DockTabStoreDependencies {
|
interface DockTabStoreDependencies {
|
||||||
createStorage: <T>(storageKey: string, options: DockTabStorageState<T>) => StorageHelper<DockTabStorageState<T>>;
|
createStorage: CreateStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DockTabStore<T> {
|
export class DockTabStore<T> {
|
||||||
protected storage?: StorageHelper<DockTabStorageState<T>>;
|
protected storage?: StorageLayer<DockTabStorageState<T>>;
|
||||||
private data = observable.map<TabId, T>();
|
private data = observable.map<TabId, T>();
|
||||||
|
|
||||||
constructor(protected dependencies: DockTabStoreDependencies, protected options: DockTabStoreOptions) {
|
constructor(protected dependencies: DockTabStoreDependencies, protected options: DockTabStoreOptions) {
|
||||||
@ -41,7 +42,7 @@ export class DockTabStore<T> {
|
|||||||
|
|
||||||
// auto-save to local-storage
|
// auto-save to local-storage
|
||||||
if (storageKey) {
|
if (storageKey) {
|
||||||
const storage = this.storage = this.dependencies.createStorage<T>(storageKey, {});
|
const storage = this.storage = this.dependencies.createStorage(storageKey, {});
|
||||||
|
|
||||||
storage.whenReady.then(() => {
|
storage.whenReady.then(() => {
|
||||||
this.data.replace(storage.value);
|
this.data.replace(storage.value);
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import * as uuid from "uuid";
|
import * as uuid from "uuid";
|
||||||
import { action, comparer, computed, makeObservable, observable, reaction, runInAction } from "mobx";
|
import { action, comparer, computed, makeObservable, observable, reaction, runInAction } from "mobx";
|
||||||
import type { StorageHelper } from "../../../utils";
|
import type { StorageLayer } from "../../../utils";
|
||||||
import { autoBind } from "../../../utils";
|
import { autoBind } from "../../../utils";
|
||||||
import throttle from "lodash/throttle";
|
import throttle from "lodash/throttle";
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ export interface DockTabCloseEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
readonly storage: StorageHelper<DockStorageState>;
|
readonly storage: StorageLayer<DockStorageState>;
|
||||||
readonly tabDataClearers: Record<TabKind, (tabId: TabId) => void>;
|
readonly tabDataClearers: Record<TabKind, (tabId: TabId) => void>;
|
||||||
readonly tabDataValidator: Partial<Record<TabKind, (tabId: TabId) => boolean>>;
|
readonly tabDataValidator: Partial<Record<TabKind, (tabId: TabId) => boolean>>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,11 +3,10 @@
|
|||||||
* 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 type { DockTabStorageState } from "../dock-tab-store/dock-tab.store";
|
|
||||||
import { DockTabStore } from "../dock-tab-store/dock-tab.store";
|
import { DockTabStore } from "../dock-tab-store/dock-tab.store";
|
||||||
import type { StorageHelper } from "../../../utils";
|
|
||||||
import type { TabId } from "../dock/store";
|
import type { TabId } from "../dock/store";
|
||||||
import { logTabDataValidator } from "./log-tab-data.validator";
|
import { logTabDataValidator } from "./log-tab-data.validator";
|
||||||
|
import type { CreateStorage } from "../../../utils/create-storage/create-storage";
|
||||||
|
|
||||||
export interface LogTabOwnerRef {
|
export interface LogTabOwnerRef {
|
||||||
/**
|
/**
|
||||||
@ -58,7 +57,7 @@ export interface LogTabData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
createStorage: <T>(storageKey: string, options: DockTabStorageState<T>) => StorageHelper<DockTabStorageState<T>>;
|
createStorage: CreateStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LogTabStore extends DockTabStore<LogTabData> {
|
export class LogTabStore extends DockTabStore<LogTabData> {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import "./drawer.scss";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { clipboard } from "electron";
|
import { clipboard } from "electron";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import type { StorageHelper } from "../../utils";
|
import type { StorageLayer } from "../../utils";
|
||||||
import { cssNames, noop } from "../../utils";
|
import { cssNames, noop } from "../../utils";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import type { AnimateName } from "../animate";
|
import type { AnimateName } from "../animate";
|
||||||
@ -63,7 +63,7 @@ export const resizingAnchorProps: Record<DrawerPosition, [ResizeDirection, Resiz
|
|||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
history: History;
|
history: History;
|
||||||
drawerStorage: StorageHelper<{ width: number }>;
|
drawerStorage: StorageLayer<{ width: number }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NonInjectedDrawer extends React.Component<DrawerProps & Dependencies & typeof defaultProps, State> {
|
class NonInjectedDrawer extends React.Component<DrawerProps & Dependencies & typeof defaultProps, State> {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import React from "react";
|
|||||||
import { computed, makeObservable, untracked } from "mobx";
|
import { computed, makeObservable, untracked } from "mobx";
|
||||||
import type { ConfirmDialogParams } from "../confirm-dialog";
|
import type { ConfirmDialogParams } from "../confirm-dialog";
|
||||||
import type { TableCellProps, TableProps, TableRowProps, TableSortCallbacks } from "../table";
|
import type { TableCellProps, TableProps, TableRowProps, TableSortCallbacks } from "../table";
|
||||||
import type { IClassName, SingleOrMany, StorageHelper } from "../../utils";
|
import type { IClassName, SingleOrMany, StorageLayer } from "../../utils";
|
||||||
import { autoBind, cssNames, noop } from "../../utils";
|
import { autoBind, cssNames, noop } from "../../utils";
|
||||||
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
|
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
|
||||||
import type { ItemObject } from "../../../common/item.store";
|
import type { ItemObject } from "../../../common/item.store";
|
||||||
@ -65,7 +65,7 @@ export type ItemListStore<I extends ItemObject, PreLoadStores extends boolean> =
|
|||||||
}) & (
|
}) & (
|
||||||
PreLoadStores extends true
|
PreLoadStores extends true
|
||||||
? {
|
? {
|
||||||
loadAll: (selectedNamespaces: string[]) => Promise<void>;
|
loadAll: (selectedNamespaces: readonly string[]) => Promise<void>;
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
loadAll?: unknown;
|
loadAll?: unknown;
|
||||||
@ -149,9 +149,13 @@ const defaultProps: Partial<ItemListLayoutProps<ItemObject, true>> = {
|
|||||||
failedToLoadMessage: "Failed to load items",
|
failedToLoadMessage: "Failed to load items",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface ItemListLayoutStorage {
|
||||||
|
showFilters: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
namespaceStore: NamespaceStore;
|
namespaceStore: NamespaceStore;
|
||||||
itemListLayoutStorage: StorageHelper<{ showFilters: boolean }>;
|
itemListLayoutStorage: StorageLayer<ItemListLayoutStorage>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
|
|||||||
@ -7,16 +7,13 @@ import styles from "./main-layout.module.scss";
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import type { StorageHelper } from "../../utils";
|
import type { StorageLayer } from "../../utils";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { ErrorBoundary } from "../error-boundary";
|
import { ErrorBoundary } from "../error-boundary";
|
||||||
import { ResizeDirection, ResizeGrowthDirection, ResizeSide, ResizingAnchor } from "../resizing-anchor";
|
import { ResizeDirection, ResizeGrowthDirection, ResizeSide, ResizingAnchor } from "../resizing-anchor";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import type {
|
import type { SidebarStorageState } from "./sidebar-storage/sidebar-storage.injectable";
|
||||||
SidebarStorageState } from "./sidebar-storage/sidebar-storage.injectable";
|
import sidebarStorageInjectable, { defaultSidebarWidth } from "./sidebar-storage/sidebar-storage.injectable";
|
||||||
import sidebarStorageInjectable, {
|
|
||||||
defaultSidebarWidth,
|
|
||||||
} from "./sidebar-storage/sidebar-storage.injectable";
|
|
||||||
|
|
||||||
export interface MainLayoutProps {
|
export interface MainLayoutProps {
|
||||||
sidebar: React.ReactNode;
|
sidebar: React.ReactNode;
|
||||||
@ -31,7 +28,7 @@ export interface MainLayoutProps {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
sidebarStorage: StorageHelper<SidebarStorageState>;
|
sidebarStorage: StorageLayer<SidebarStorageState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
|
|||||||
@ -7,20 +7,18 @@ import "./sidebar-item.scss";
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { computed, makeObservable } from "mobx";
|
import { computed, makeObservable } from "mobx";
|
||||||
import type { StorageHelper } from "../../utils";
|
import type { StorageLayer } from "../../utils";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { NavLink } from "react-router-dom";
|
import { NavLink } from "react-router-dom";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import type {
|
import type { SidebarStorageState } from "./sidebar-storage/sidebar-storage.injectable";
|
||||||
SidebarStorageState,
|
|
||||||
} from "./sidebar-storage/sidebar-storage.injectable";
|
|
||||||
import sidebarStorageInjectable from "./sidebar-storage/sidebar-storage.injectable";
|
import sidebarStorageInjectable from "./sidebar-storage/sidebar-storage.injectable";
|
||||||
import type { HierarchicalSidebarItem } from "./sidebar-items.injectable";
|
import type { HierarchicalSidebarItem } from "./sidebar-items.injectable";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
sidebarStorage: StorageHelper<SidebarStorageState>;
|
sidebarStorage: StorageLayer<SidebarStorageState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SidebarItemProps {
|
export interface SidebarItemProps {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
* 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 type { StorageHelper } from "../../../utils";
|
import type { StorageLayer } from "../../../utils";
|
||||||
import type { TableSortParams } from "../table";
|
import type { TableSortParams } from "../table";
|
||||||
|
|
||||||
export interface TableStorageModel {
|
export interface TableStorageModel {
|
||||||
@ -12,7 +12,7 @@ export interface TableStorageModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
storage: StorageHelper<TableStorageModel>;
|
storage: StorageLayer<TableStorageModel>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TableModel {
|
export class TableModel {
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import glob from "glob";
|
import glob from "glob";
|
||||||
import { memoize, noop } from "lodash/fp";
|
import { isEqual, isPlainObject, memoize, noop } from "lodash/fp";
|
||||||
import { createContainer } from "@ogre-tools/injectable";
|
import { createContainer } from "@ogre-tools/injectable";
|
||||||
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||||
import getValueFromRegisteredChannelInjectable from "./app-paths/get-value-from-registered-channel/get-value-from-registered-channel.injectable";
|
import getValueFromRegisteredChannelInjectable from "./app-paths/get-value-from-registered-channel/get-value-from-registered-channel.injectable";
|
||||||
@ -35,6 +35,10 @@ import { joinPathsFake } from "../common/test-utils/join-paths-fake";
|
|||||||
import hotbarStoreInjectable from "../common/hotbar-store.injectable";
|
import hotbarStoreInjectable from "../common/hotbar-store.injectable";
|
||||||
import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-spawning-pool.injectable";
|
import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-spawning-pool.injectable";
|
||||||
import hostedClusterIdInjectable from "../common/cluster-store/hosted-cluster-id.injectable";
|
import hostedClusterIdInjectable from "../common/cluster-store/hosted-cluster-id.injectable";
|
||||||
|
import createStorageInjectable from "./utils/create-storage/create-storage.injectable";
|
||||||
|
import { observable, toJS } from "mobx";
|
||||||
|
import type { Draft } from "immer";
|
||||||
|
import { produce, isDraft } from "immer";
|
||||||
|
|
||||||
export const getDiForUnitTesting = (
|
export const getDiForUnitTesting = (
|
||||||
{ doGeneralOverrides } = { doGeneralOverrides: false },
|
{ doGeneralOverrides } = { doGeneralOverrides: false },
|
||||||
@ -59,7 +63,41 @@ export const getDiForUnitTesting = (
|
|||||||
di.override(isWindowsInjectable, () => false);
|
di.override(isWindowsInjectable, () => false);
|
||||||
di.override(isLinuxInjectable, () => false);
|
di.override(isLinuxInjectable, () => false);
|
||||||
|
|
||||||
di.override(terminalSpawningPoolInjectable, () => new HTMLElement());
|
di.override(terminalSpawningPoolInjectable, () => document.createElement("div"));
|
||||||
|
di.override(createStorageInjectable, () => function <MockT>(key: string, defaultValue: MockT) {
|
||||||
|
const srcValue = observable.box(defaultValue);
|
||||||
|
|
||||||
|
return {
|
||||||
|
get: () => srcValue.get(),
|
||||||
|
isDefaultValue: val => isEqual(val, defaultValue),
|
||||||
|
merge: (value: Partial<MockT> | ((draft: Draft<MockT>) => void | Partial<MockT>)) => {
|
||||||
|
const nextValue = produce(toJS(srcValue.get()), (draft) => {
|
||||||
|
|
||||||
|
if (typeof value == "function") {
|
||||||
|
const newValue = value(draft);
|
||||||
|
|
||||||
|
// merge returned plain objects from `value-as-callback` usage
|
||||||
|
// otherwise `draft` can be just modified inside a callback without returning any value (void)
|
||||||
|
if (newValue && !isDraft(newValue)) {
|
||||||
|
Object.assign(draft, newValue);
|
||||||
|
}
|
||||||
|
} else if (isPlainObject(value)) {
|
||||||
|
Object.assign(draft, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return draft;
|
||||||
|
});
|
||||||
|
|
||||||
|
srcValue.set(nextValue);
|
||||||
|
},
|
||||||
|
reset: () => srcValue.set(defaultValue),
|
||||||
|
set: (val: MockT) => srcValue.set(val),
|
||||||
|
get value() {
|
||||||
|
return srcValue.get();
|
||||||
|
},
|
||||||
|
whenReady: Promise.resolve(),
|
||||||
|
};
|
||||||
|
});
|
||||||
di.override(hostedClusterIdInjectable, () => undefined);
|
di.override(hostedClusterIdInjectable, () => undefined);
|
||||||
|
|
||||||
di.override(getAbsolutePathInjectable, () => getAbsolutePathFake);
|
di.override(getAbsolutePathInjectable, () => getAbsolutePathFake);
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { action, makeObservable, observable, reaction } from "mobx";
|
import { action, makeObservable, observable, reaction } from "mobx";
|
||||||
import { ItemStore } from "../../../common/item.store";
|
import { ItemStore } from "../../../common/item.store";
|
||||||
import type { StorageHelper } from "../../utils";
|
import type { StorageLayer } from "../../utils";
|
||||||
import { autoBind, disposer } from "../../utils";
|
import { autoBind, disposer } from "../../utils";
|
||||||
import type { ForwardedPort } from "../port-forward-item";
|
import type { ForwardedPort } from "../port-forward-item";
|
||||||
import { PortForwardItem } from "../port-forward-item";
|
import { PortForwardItem } from "../port-forward-item";
|
||||||
@ -14,7 +14,7 @@ import { waitUntilFree } from "tcp-port-used";
|
|||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
storage: StorageHelper<ForwardedPort[] | undefined>;
|
storage: StorageLayer<ForwardedPort[] | undefined>;
|
||||||
notifyErrorPortForwarding: (message: string) => void;
|
notifyErrorPortForwarding: (message: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
import { observable, reaction } from "mobx";
|
import { observable, reaction } from "mobx";
|
||||||
import { StorageHelper } from "../storageHelper";
|
import { StorageHelper } from "../storageHelper";
|
||||||
import { delay } from "../../../common/utils/delay";
|
import { delay } from "../../../common/utils/delay";
|
||||||
|
import { toJS } from "../../../common/utils";
|
||||||
|
|
||||||
interface StorageModel {
|
interface StorageModel {
|
||||||
[prop: string]: any /*json-serializable*/;
|
[prop: string]: any /*json-serializable*/;
|
||||||
@ -131,7 +132,7 @@ describe("renderer/utils/StorageHelper", () => {
|
|||||||
it("storage.get() is observable", () => {
|
it("storage.get() is observable", () => {
|
||||||
expect(storageHelper.get()).toEqual(defaultValue);
|
expect(storageHelper.get()).toEqual(defaultValue);
|
||||||
|
|
||||||
reaction(() => storageHelper.toJSON(), change => {
|
reaction(() => toJS(storageHelper.get()), change => {
|
||||||
observedChanges.push(change);
|
observedChanges.push(change);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -15,20 +15,19 @@ import hostedClusterIdInjectable from "../../../common/cluster-store/hosted-clus
|
|||||||
const createStorageInjectable = getInjectable({
|
const createStorageInjectable = getInjectable({
|
||||||
id: "create-storage",
|
id: "create-storage",
|
||||||
|
|
||||||
instantiate: (di) =>
|
instantiate: (di) => createStorage({
|
||||||
createStorage({
|
storage: observable({
|
||||||
storage: observable({
|
initialized: false,
|
||||||
initialized: false,
|
loaded: false,
|
||||||
loaded: false,
|
data: {},
|
||||||
data: {} as Record<string /*key*/, any>, // json-serializable
|
|
||||||
}),
|
|
||||||
readJsonFile: di.inject(readJsonFileInjectable),
|
|
||||||
writeJsonFile: di.inject(writeJsonFileInjectable),
|
|
||||||
logger: di.inject(loggerInjectable),
|
|
||||||
directoryForLensLocalStorage: di.inject(directoryForLensLocalStorageInjectable),
|
|
||||||
getAbsolutePath: di.inject(getAbsolutePathInjectable),
|
|
||||||
hostedClusterId: di.inject(hostedClusterIdInjectable),
|
|
||||||
}),
|
}),
|
||||||
|
readJsonFile: di.inject(readJsonFileInjectable),
|
||||||
|
writeJsonFile: di.inject(writeJsonFileInjectable),
|
||||||
|
logger: di.inject(loggerInjectable),
|
||||||
|
directoryForLensLocalStorage: di.inject(directoryForLensLocalStorageInjectable),
|
||||||
|
getAbsolutePath: di.inject(getAbsolutePathInjectable),
|
||||||
|
hostedClusterId: di.inject(hostedClusterIdInjectable),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default createStorageInjectable;
|
export default createStorageInjectable;
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
// Keeps window.localStorage state in external JSON-files.
|
// Keeps window.localStorage state in external JSON-files.
|
||||||
// Because app creates random port between restarts => storage session wiped out each time.
|
// Because app creates random port between restarts => storage session wiped out each time.
|
||||||
import { comparer, reaction, toJS, when } from "mobx";
|
import { comparer, reaction, toJS, when } from "mobx";
|
||||||
|
import type { StorageLayer } from "../storageHelper";
|
||||||
import { StorageHelper } from "../storageHelper";
|
import { StorageHelper } from "../storageHelper";
|
||||||
import { isTestEnv } from "../../../common/vars";
|
import { isTestEnv } from "../../../common/vars";
|
||||||
import type { JsonObject, JsonValue } from "type-fest";
|
import type { JsonObject, JsonValue } from "type-fest";
|
||||||
@ -22,6 +23,8 @@ interface Dependencies {
|
|||||||
hostedClusterId: string | undefined;
|
hostedClusterId: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CreateStorage = <T>(key: string, defaultValue: T) => StorageLayer<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a helper for saving data under the "key" intended for window.localStorage
|
* Creates a helper for saving data under the "key" intended for window.localStorage
|
||||||
*/
|
*/
|
||||||
@ -33,7 +36,7 @@ export const createStorage = ({
|
|||||||
readJsonFile,
|
readJsonFile,
|
||||||
writeJsonFile,
|
writeJsonFile,
|
||||||
hostedClusterId,
|
hostedClusterId,
|
||||||
}: Dependencies) => <T>(key: string, defaultValue: T) => {
|
}: Dependencies): CreateStorage => (key, defaultValue) => {
|
||||||
const { logPrefix } = StorageHelper;
|
const { logPrefix } = StorageHelper;
|
||||||
|
|
||||||
if (!storage.initialized) {
|
if (!storage.initialized) {
|
||||||
@ -78,7 +81,7 @@ export const createStorage = ({
|
|||||||
.catch(error => logger.error(`${logPrefix} Failed to initialize storage: ${error}`));
|
.catch(error => logger.error(`${logPrefix} Failed to initialize storage: ${error}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new StorageHelper<T>(key, {
|
return new StorageHelper(key, {
|
||||||
autoInit: true,
|
autoInit: true,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
storage: {
|
storage: {
|
||||||
|
|||||||
@ -24,7 +24,17 @@ export interface StorageHelperOptions<T> {
|
|||||||
defaultValue: T;
|
defaultValue: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StorageHelper<T> {
|
export interface StorageLayer<T> {
|
||||||
|
isDefaultValue(val: T): boolean;
|
||||||
|
get(): T;
|
||||||
|
readonly value: T;
|
||||||
|
readonly whenReady: Promise<void>;
|
||||||
|
set(value: T): void;
|
||||||
|
reset(): void;
|
||||||
|
merge(value: Partial<T> | ((draft: Draft<T>) => Partial<T> | void)): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StorageHelper<T> implements StorageLayer<T> {
|
||||||
static logPrefix = "[StorageHelper]:";
|
static logPrefix = "[StorageHelper]:";
|
||||||
readonly storage: StorageAdapter<T>;
|
readonly storage: StorageAdapter<T>;
|
||||||
|
|
||||||
@ -140,7 +150,7 @@ export class StorageHelper<T> {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
merge(value: Partial<T> | ((draft: Draft<T>) => Partial<T> | void)) {
|
merge(value: Partial<T> | ((draft: Draft<T>) => Partial<T> | void)) {
|
||||||
const nextValue = produce<T>(this.toJSON(), (draft: Draft<T>) => {
|
const nextValue = produce<T>(toJS(this.get()), (draft) => {
|
||||||
|
|
||||||
if (typeof value == "function") {
|
if (typeof value == "function") {
|
||||||
const newValue = value(draft);
|
const newValue = value(draft);
|
||||||
@ -159,8 +169,4 @@ export class StorageHelper<T> {
|
|||||||
|
|
||||||
this.set(nextValue);
|
this.set(nextValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): T {
|
|
||||||
return toJS(this.get());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user