diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 0ca6f45b39..9548e494f7 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -73,8 +73,8 @@ export class ReleaseStore extends ItemStore { } } - async loadSelectedNamespaces(): Promise { - return this.loadAll(namespaceStore.getContextNamespaces()); + async loadFromContextNamespaces(): Promise { + return this.loadAll(namespaceStore.contextNamespaces); } async loadItems(namespaces: string[]) { @@ -86,7 +86,7 @@ export class ReleaseStore extends ItemStore { async create(payload: IReleaseCreatePayload) { const response = await helmReleasesApi.create(payload); - if (this.isLoaded) this.loadSelectedNamespaces(); + if (this.isLoaded) this.loadFromContextNamespaces(); return response; } @@ -94,7 +94,7 @@ export class ReleaseStore extends ItemStore { async update(name: string, namespace: string, payload: IReleaseUpdatePayload) { const response = await helmReleasesApi.update(name, namespace, payload); - if (this.isLoaded) this.loadSelectedNamespaces(); + if (this.isLoaded) this.loadFromContextNamespaces(); return response; } @@ -102,7 +102,7 @@ export class ReleaseStore extends ItemStore { async rollback(name: string, namespace: string, revision: number) { const response = await helmReleasesApi.rollback(name, namespace, revision); - if (this.isLoaded) this.loadSelectedNamespaces(); + if (this.isLoaded) this.loadFromContextNamespaces(); return response; } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index 1503267c24..4a9290eb4e 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -30,7 +30,7 @@ export class CrdResources extends React.Component { const { store } = this; if (store && !store.isLoading && !store.isLoaded) { - store.loadContextNamespaces(); + store.loadAllFromContextNamespaces(); } }) ]); diff --git a/src/renderer/components/+events/kube-event-details.tsx b/src/renderer/components/+events/kube-event-details.tsx index b8b3058fb0..9ac4587395 100644 --- a/src/renderer/components/+events/kube-event-details.tsx +++ b/src/renderer/components/+events/kube-event-details.tsx @@ -14,7 +14,7 @@ export interface KubeEventDetailsProps { @observer export class KubeEventDetails extends React.Component { async componentDidMount() { - eventStore.loadContextNamespaces(); + eventStore.loadAllFromContextNamespaces(); } render() { diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index c7a4a0e845..c8cf0f6bcb 100644 --- a/src/renderer/components/+namespaces/namespace-details.tsx +++ b/src/renderer/components/+namespaces/namespace-details.tsx @@ -32,8 +32,8 @@ export class NamespaceDetails extends React.Component { } componentDidMount() { - resourceQuotaStore.loadContextNamespaces(); - limitRangeStore.loadContextNamespaces(); + resourceQuotaStore.loadAllFromContextNamespaces(); + limitRangeStore.loadAllFromContextNamespaces(); } render() { diff --git a/src/renderer/components/+namespaces/namespace-select.tsx b/src/renderer/components/+namespaces/namespace-select.tsx index c3d26ba192..27fbb8a311 100644 --- a/src/renderer/components/+namespaces/namespace-select.tsx +++ b/src/renderer/components/+namespaces/namespace-select.tsx @@ -82,7 +82,7 @@ export class NamespaceSelect extends React.Component { @observer export class NamespaceSelectFilter extends React.Component { @computed get placeholder(): React.ReactNode { - const namespaces = namespaceStore.getContextNamespaces(); + const namespaces = namespaceStore.contextNamespaces; switch (namespaces.length) { case 0: diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index 2b5cf3cbbc..4ea270a3af 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -1,10 +1,9 @@ -import { action, comparer, computed, IReactionDisposer, IReactionOptions, observable, reaction, toJS, when } from "mobx"; +import { action, comparer, computed, IReactionDisposer, IReactionOptions, observable, reaction } from "mobx"; import { autobind, createStorage } from "../../utils"; import { KubeObjectStore, KubeObjectStoreLoadingParams } from "../../kube-object.store"; import { Namespace, namespacesApi } from "../../api/endpoints/namespaces.api"; import { createPageParam } from "../../navigation"; import { apiManager } from "../../api/api-manager"; -import { clusterStore, getHostedCluster } from "../../../common/cluster-store"; const storage = createStorage("context_namespaces", []); @@ -35,9 +34,6 @@ export class NamespaceStore extends KubeObjectStore { api = namespacesApi; @observable private contextNs = observable.set(); - @observable isReady = false; - - whenReady = when(() => this.isReady); constructor() { super(); @@ -45,15 +41,12 @@ export class NamespaceStore extends KubeObjectStore { } private async init() { - await clusterStore.whenLoaded; - if (!getHostedCluster()) return; - await getHostedCluster().whenReady; // wait for cluster-state from main + await this.resolveCluster(); + if (!this.cluster) return; // skip for non-cluster context window this.setContext(this.initialNamespaces); this.autoLoadAllowedNamespaces(); this.autoUpdateUrlAndLocalStorage(); - - this.isReady = true; } public onContextChange(callback: (contextNamespaces: string[]) => void, opts: IReactionOptions = {}): IReactionDisposer { @@ -79,10 +72,6 @@ export class NamespaceStore extends KubeObjectStore { }); } - @computed get allowedNamespaces(): string[] { - return toJS(getHostedCluster().allowedNamespaces); - } - @computed private get initialNamespaces(): string[] { const namespaces = new Set(this.allowedNamespaces); @@ -103,27 +92,26 @@ export class NamespaceStore extends KubeObjectStore { return []; } - getContextNamespaces(): string[] { + @computed get allowedNamespaces(): string[] { + return Array.from(new Set([ + ...(this.cluster?.allowedNamespaces ?? []), // loaded names from main, updating every 30s and thus might be stale + ...this.items.map(item => item.getName()), // loaded names from hosted cluster + ].flat())); + } + + @computed get contextNamespaces(): string[] { const namespaces = Array.from(this.contextNs); - // show all namespaces when nothing selected if (!namespaces.length) { - // return actual namespaces list since "allowedNamespaces" updating every 30s in cluster and thus might be stale - if (this.isLoaded) { - return this.items.map(namespace => namespace.getName()); - } - - return this.allowedNamespaces; + return this.allowedNamespaces; // show all namespaces when nothing selected } return namespaces; } getSubscribeApis() { - const { accessibleNamespaces } = getHostedCluster(); - // if user has given static list of namespaces let's not start watches because watch adds stuff that's not wanted - if (accessibleNamespaces.length > 0) { + if (this.cluster?.accessibleNamespaces.length > 0) { return []; } @@ -152,7 +140,7 @@ export class NamespaceStore extends KubeObjectStore { } @action - resetContext(){ + resetContext() { this.contextNs.clear(); } diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index fb5da8b20f..455005db25 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -29,7 +29,7 @@ export class NodeDetails extends React.Component { }); async componentDidMount() { - podsStore.loadContextNamespaces(); + podsStore.loadAllFromContextNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx index 97e4f9d9e3..fde70e1290 100644 --- a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx +++ b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx @@ -80,7 +80,7 @@ export class AddRoleBindingDialog extends React.Component { ]; this.isLoading = true; - await Promise.all(stores.map(store => store.loadContextNamespaces())); + await Promise.all(stores.map(store => store.loadAllFromContextNamespaces())); this.isLoading = false; } diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx index c5c31ef3d2..6ac5e474b7 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx @@ -20,7 +20,7 @@ interface Props extends KubeObjectDetailsProps { @observer export class CronJobDetails extends React.Component { async componentDidMount() { - jobStore.loadContextNamespaces(); + jobStore.loadAllFromContextNamespaces(); } render() { diff --git a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx index 4435f718ec..68f20e4b54 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx @@ -30,7 +30,7 @@ export class DaemonSetDetails extends React.Component { }); componentDidMount() { - podsStore.loadContextNamespaces(); + podsStore.loadAllFromContextNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index 72f2013c9b..426d8f40c6 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -31,7 +31,7 @@ export class DeploymentDetails extends React.Component { }); componentDidMount() { - podsStore.loadContextNamespaces(); + podsStore.loadAllFromContextNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/+workloads-jobs/job-details.tsx b/src/renderer/components/+workloads-jobs/job-details.tsx index 1dce500fe6..21a4edd4e2 100644 --- a/src/renderer/components/+workloads-jobs/job-details.tsx +++ b/src/renderer/components/+workloads-jobs/job-details.tsx @@ -25,7 +25,7 @@ interface Props extends KubeObjectDetailsProps { @observer export class JobDetails extends React.Component { async componentDidMount() { - podsStore.loadContextNamespaces(); + podsStore.loadAllFromContextNamespaces(); } render() { diff --git a/src/renderer/components/+workloads-overview/overview-statuses.tsx b/src/renderer/components/+workloads-overview/overview-statuses.tsx index 33e5aa37c5..082f24db20 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -27,7 +27,7 @@ export class OverviewStatuses extends React.Component { @autobind() renderWorkload(resource: KubeResource): React.ReactElement { const store = workloadStores[resource]; - const items = store.getAllByNs(namespaceStore.getContextNamespaces()); + const items = store.getAllByNs(namespaceStore.contextNamespaces); return (
diff --git a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx index 6b68ffa02d..c0a4ddc549 100644 --- a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx +++ b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx @@ -29,7 +29,7 @@ export class ReplicaSetDetails extends React.Component { }); async componentDidMount() { - podsStore.loadContextNamespaces(); + podsStore.loadAllFromContextNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx index 3088516114..c386f32503 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx @@ -30,7 +30,7 @@ export class StatefulSetDetails extends React.Component { }); componentDidMount() { - podsStore.loadContextNamespaces(); + podsStore.loadAllFromContextNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 2236b3d6be..8dd711e4ed 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -76,10 +76,9 @@ export class App extends React.Component { }); whatInput.ask(); // Start to monitor user input device - await namespaceStore.whenReady; await kubeWatchApi.init({ - getCluster: getHostedCluster, - getNamespaces: namespaceStore.getContextNamespaces, + getCluster: () => getHostedCluster(), + getNamespaces: () => namespaceStore.contextNamespaces, }); } diff --git a/src/renderer/components/dock/upgrade-chart.store.ts b/src/renderer/components/dock/upgrade-chart.store.ts index f609420d9d..63468f3180 100644 --- a/src/renderer/components/dock/upgrade-chart.store.ts +++ b/src/renderer/components/dock/upgrade-chart.store.ts @@ -80,7 +80,7 @@ export class UpgradeChartStore extends DockTabStore { const values = this.values.getData(tabId); await Promise.all([ - !releaseStore.isLoaded && releaseStore.loadSelectedNamespaces(), + !releaseStore.isLoaded && releaseStore.loadFromContextNamespaces(), !values && this.loadValues(tabId) ]); } diff --git a/src/renderer/components/item-object-list/item-list-layout.tsx b/src/renderer/components/item-object-list/item-list-layout.tsx index ac0d2ea635..0db20c8777 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -138,7 +138,8 @@ export class ItemListLayout extends React.Component { const { store, dependentStores } = this.props; const stores = Array.from(new Set([store, ...dependentStores])); - stores.forEach(store => store.loadAll(namespaceStore.getContextNamespaces())); + // loads context namespaces by default (see also: ``) + stores.forEach(store => store.loadAll(namespaceStore.contextNamespaces)); } private filterCallbacks: { [type: string]: ItemsFilter } = { diff --git a/src/renderer/components/item-object-list/page-filters.store.ts b/src/renderer/components/item-object-list/page-filters.store.ts index 8f5fa2c9eb..57651e6a26 100644 --- a/src/renderer/components/item-object-list/page-filters.store.ts +++ b/src/renderer/components/item-object-list/page-filters.store.ts @@ -27,10 +27,11 @@ export class PageFiltersStore { this.syncWithContextNamespace(); } + // todo: refactor protected syncWithContextNamespace() { const disposers = [ reaction(() => this.getValues(FilterType.NAMESPACE), filteredNs => { - if (filteredNs.length !== namespaceStore.getContextNamespaces().length) { + if (filteredNs.length !== namespaceStore.contextNamespaces.length) { namespaceStore.setContext(filteredNs); } }), diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index c3fc715a7c..de78609813 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -40,7 +40,7 @@ interface Props { @observer export class Sidebar extends React.Component { async componentDidMount() { - crdStore.loadContextNamespaces(); + crdStore.loadAllFromContextNamespaces(); } renderCustomResources() { diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index 6ecc8cd103..3eb4d0c147 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -20,6 +20,7 @@ export abstract class KubeObjectStore extends ItemSt abstract api: KubeApi; public readonly limit?: number; public readonly bufferSize: number = 50000; + @observable.ref protected cluster: Cluster; constructor() { super(); @@ -29,29 +30,27 @@ export abstract class KubeObjectStore extends ItemSt // TODO: detach / remove circular dependency @observable.ref private namespaceStore: NamespaceStore; - private async resolveNamespaceStore(): Promise { + protected async resolveNamespaceStore(): Promise { const { namespaceStore } = await import("./components/+namespaces/namespace.store"); - await namespaceStore.whenReady; this.namespaceStore = namespaceStore; return namespaceStore; } - // TODO: detach / inject dependency as in kube-watch-api - @observable.ref private cluster: Cluster; - - private async resolveCluster(): Promise { - const { getHostedCluster } = await import("../common/cluster-store"); + protected async resolveCluster(): Promise { + const { getHostedCluster, clusterStore } = await import("../common/cluster-store"); + await clusterStore.whenLoaded; this.cluster = getHostedCluster(); + await this.cluster.whenReady; return this.cluster; } // TODO: figure out how to transparently replace with this.items @computed get contextItems(): T[] { - const contextNamespaces = this.namespaceStore?.getContextNamespaces() ?? []; // not loaded + const contextNamespaces = this.namespaceStore?.contextNamespaces ?? []; // not loaded return this.items.filter((item: T) => !item.getNs() || contextNamespaces.includes(item.getId())); } @@ -132,15 +131,15 @@ export abstract class KubeObjectStore extends ItemSt } @action - async loadAll(namespaces: string[] = [], { replace = false /*partial update*/ } = {}): Promise { + async loadAll(namespaces?: string[], { replace = false /*partial update*/ } = {}): Promise { this.isLoading = true; try { // load all available namespaces by default - if (!namespaces.length) { + if (!namespaces?.length) { const namespaceStore = await this.resolveNamespaceStore(); - namespaces = namespaceStore.getContextNamespaces(); + namespaces = namespaceStore.allowedNamespaces; // load all by default if list not provided } const items = await this.loadItems({ namespaces, api: this.api }); @@ -177,8 +176,8 @@ export abstract class KubeObjectStore extends ItemSt return items; } - async loadContextNamespaces(): Promise { - return this.loadAll(this.namespaceStore?.getContextNamespaces()); + async loadAllFromContextNamespaces(): Promise { + return this.loadAll(this.namespaceStore?.contextNamespaces); } protected resetOnError(error: any) {