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

Move everything else related to selecting namespaces into context

- Use only the context for the namespace-select-filter-model

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-03-03 16:39:56 -05:00
parent d7474fe443
commit 3fd68bfcc1
6 changed files with 78 additions and 24 deletions

View File

@ -7,10 +7,25 @@
* This type is used for KubeObjectStores
*/
export interface ClusterContext {
readonly allNamespaces: string[]; // available / allowed namespaces from cluster.ts
readonly contextNamespaces: string[]; // selected by user (see: namespace-select.tsx)
/**
* A computed getter for all the namespaces that this cluster knows about
*/
readonly allNamespaces: string[];
/**
* The computed getter of namespaces that are currently selected
*/
readonly contextNamespaces: string[];
readonly hasSelectedAll: boolean;
isLoadingAll(namespaces: string[]): boolean;
isGlobalWatchEnabled(): boolean;
}
export interface NamespaceScopedClusterContext extends ClusterContext {
selectAllNamespaces(): void;
toggleNamespace(namespace: string): void;
selectNamespace(namespace: string): void;
deselectNamespace(namespace: string): void;
}

View File

@ -3,18 +3,21 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import type { ClusterContext } from "./cluster-frame-context";
import type { NamespaceScopedClusterContext } from "./cluster-frame-context";
import namespaceStoreInjectable from "../components/+namespaces/store.injectable";
import hostedClusterInjectable from "./hosted-cluster.injectable";
import assert from "assert";
import { computed } from "mobx";
import selectedNamespaceStorageInjectable from "../components/+namespaces/namespace-storage.injectable";
import { toggle } from "../utils";
const clusterFrameContextForNamespacedResourcesInjectable = getInjectable({
id: "cluster-frame-context-for-namespaced-resources",
instantiate: (di): ClusterContext => {
instantiate: (di): NamespaceScopedClusterContext => {
const cluster = di.inject(hostedClusterInjectable);
const namespaceStore = di.inject(namespaceStoreInjectable);
const selectedNamespaceStorage = di.inject(selectedNamespaceStorageInjectable);
assert(cluster, "This can only be injected within a cluster frame");
@ -25,20 +28,37 @@ const clusterFrameContextForNamespacedResourcesInjectable = getInjectable({
}
if (namespaceStore.items.length > 0) {
// namespaces from kubernetes api
// namespaces from kubernetes api
return namespaceStore.items.map((namespace) => namespace.getName());
}
// fallback to cluster resolved namespaces because we could not load list
return cluster.allowedNamespaces.slice();
});
const contextNamespaces = computed(() => namespaceStore.contextNamespaces);
const contextNamespaces = computed(() => {
const storedState = selectedNamespaceStorage.get();
if (!storedState || storedState.length === 0) {
return allNamespaces.get();
}
const state = new Set(storedState);
const currentlyKnownNamespaces = new Set(allNamespaces.get());
for (const namespace of storedState) {
if (!currentlyKnownNamespaces.has(namespace)) {
state.delete(namespace);
}
}
return [...state];
});
const hasSelectedAll = computed(() => {
const namespaces = new Set(contextNamespaces.get());
return allNamespaces.get().length > 1
&& cluster.accessibleNamespaces.length === 0
&& allNamespaces.get().every(ns => namespaces.has(ns));
&& cluster.accessibleNamespaces.length === 0
&& allNamespaces.get().every(ns => namespaces.has(ns));
});
return {
@ -48,6 +68,24 @@ const clusterFrameContextForNamespacedResourcesInjectable = getInjectable({
&& allNamespaces.get().every(ns => namespaces.includes(ns))
),
isGlobalWatchEnabled: () => cluster.isGlobalWatchEnabled,
selectAllNamespaces: () => {
selectedNamespaceStorage.set([]);
},
selectNamespace: (namespace) => {
selectedNamespaceStorage.set([namespace]);
},
toggleNamespace: (namespace) => {
const nextState = new Set(contextNamespaces.get());
toggle(nextState, namespace);
selectedNamespaceStorage.set([...nextState]);
},
deselectNamespace: (namespace) => {
const nextState = new Set(contextNamespaces.get());
nextState.delete(namespace);
selectedNamespaceStorage.set([...nextState]);
},
get allNamespaces() {
return allNamespaces.get();
},

View File

@ -3,16 +3,16 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import namespaceStoreInjectable from "../store.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../../cluster-frame-context/for-namespaced-resources.injectable";
export type FilterByNamespace = (namespace: string) => void;
const filterByNamespaceInjectable = getInjectable({
id: "filter-by-namespace",
instantiate: (di): FilterByNamespace => {
const namespaceStore = di.inject(namespaceStoreInjectable);
const context = di.inject(clusterFrameContextForNamespacedResourcesInjectable);
return (namespace) => namespaceStore.selectSingle(namespace);
return (namespace) => context.selectNamespace(namespace);
},
});

View File

@ -4,7 +4,6 @@
*/
import { namespaceSelectFilterModelFor } from "./namespace-select-filter-model";
import { getInjectable } from "@ogre-tools/injectable";
import namespaceStoreInjectable from "../store.injectable";
import isMultiSelectionKeyInjectable from "./is-selection-key.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../../cluster-frame-context/for-namespaced-resources.injectable";
@ -12,7 +11,6 @@ const namespaceSelectFilterModelInjectable = getInjectable({
id: "namespace-select-filter-model",
instantiate: (di) => namespaceSelectFilterModelFor({
namespaceStore: di.inject(namespaceStoreInjectable),
isMultiSelectionKey: di.inject(isMultiSelectionKeyInjectable),
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}),

View File

@ -5,16 +5,15 @@
import React from "react";
import type { IComputedValue } from "mobx";
import { observable, action, computed, comparer } from "mobx";
import type { NamespaceStore } from "../store";
import type { ActionMeta, MultiValue } from "react-select";
import { Icon } from "../../icon";
import type { SelectOption } from "../../select";
import { observableCrate } from "../../../utils";
import type { IsMultiSelectionKey } from "./is-selection-key.injectable";
import type { NamespaceScopedClusterContext } from "../../../cluster-frame-context/cluster-frame-context";
interface Dependencies {
context: NamespaceScopedClusterContext;
namespaceStore: NamespaceStore;
isMultiSelectionKey: IsMultiSelectionKey;
}
@ -45,7 +44,7 @@ enum SelectMenuState {
}
export function namespaceSelectFilterModelFor(dependencies: Dependencies): NamespaceSelectFilterModel {
const { isMultiSelectionKey, namespaceStore, context } = dependencies;
const { isMultiSelectionKey, context } = dependencies;
let didToggle = false;
let isMultiSelection = false;
@ -111,7 +110,7 @@ export function namespaceSelectFilterModelFor(dependencies: Dependencies): Names
onChange: (_, action) => {
switch (action.action) {
case "clear":
namespaceStore.selectAll();
context.selectAllNamespaces();
break;
case "deselect-option":
case "select-option":
@ -119,11 +118,11 @@ export function namespaceSelectFilterModelFor(dependencies: Dependencies): Names
didToggle = true;
if (action.option.value === selectAllNamespaces) {
namespaceStore.selectAll();
context.selectAllNamespaces();
} else if (isMultiSelection) {
namespaceStore.toggleSingle(action.option.value);
context.toggleNamespace(action.option.value);
} else {
namespaceStore.selectSingle(action.option.value);
context.selectNamespace(action.option.value);
}
}
break;

View File

@ -15,6 +15,8 @@ import type { Fetch } from "../../../common/fetch/fetch.injectable";
import fetchInjectable from "../../../common/fetch/fetch.injectable";
import { Namespace } from "../../../common/k8s-api/endpoints";
import { createMockResponseFromString } from "../../../test-utils/mock-responses";
import type { NamespaceScopedClusterContext } from "../../cluster-frame-context/cluster-frame-context";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable";
import createClusterInjectable from "../../cluster/create-cluster.injectable";
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
@ -43,6 +45,7 @@ function createNamespace(name: string): Namespace {
describe("<NamespaceSelectFilter />", () => {
let di: DiContainer;
let namespaceStore: NamespaceStore;
let context: NamespaceScopedClusterContext;
let fetchMock: AsyncFnMock<Fetch>;
let result: RenderResult;
let cleanup: Disposer;
@ -69,6 +72,7 @@ describe("<NamespaceSelectFilter />", () => {
}));
namespaceStore = di.inject(namespaceStoreInjectable);
context = di.inject(clusterFrameContextForNamespacedResourcesInjectable);
const subscribeStores = di.inject(subscribeStoresInjectable);
@ -138,7 +142,7 @@ describe("<NamespaceSelectFilter />", () => {
});
it("has only 'test-2' is selected in the store", () => {
expect(namespaceStore.contextNamespaces).toEqual(["test-2"]);
expect(context.contextNamespaces).toEqual(["test-2"]);
});
it("closes menu", () => {
@ -172,7 +176,7 @@ describe("<NamespaceSelectFilter />", () => {
});
it("has only 'test-1' is selected in the store", () => {
expect(namespaceStore.contextNamespaces).toEqual(["test-1"]);
expect(context.contextNamespaces).toEqual(["test-1"]);
});
it("closes menu", () => {
@ -197,7 +201,7 @@ describe("<NamespaceSelectFilter />", () => {
});
it("has both 'test-1' and 'test-3' as selected in the store", () => {
expect(new Set(namespaceStore.contextNamespaces)).toEqual(new Set(["test-1", "test-3"]));
expect(new Set(context.contextNamespaces)).toEqual(new Set(["test-1", "test-3"]));
});
it("keeps menu open", () => {
@ -214,7 +218,7 @@ describe("<NamespaceSelectFilter />", () => {
});
it("has all of 'test-1', 'test-3', and 'test-13' selected in the store", () => {
expect(new Set(namespaceStore.contextNamespaces)).toEqual(new Set(["test-1", "test-3", "test-13"]));
expect(new Set(context.contextNamespaces)).toEqual(new Set(["test-1", "test-3", "test-13"]));
});
it("'test-13' is not sorted to the top of the list", () => {