From bd9e44109af321d0a0208a98614847d44d60f3e9 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 2 Feb 2021 16:06:01 +0200 Subject: [PATCH] Detach NamespaceStore from KubeWatchApi, proper KubeObjectStore.loadAll (rebase of #2033) Signed-off-by: Roman --- src/renderer/api/kube-watch-api.ts | 54 +++++++++---------- .../+apps-releases/release.store.ts | 14 +++-- .../+custom-resources/crd-resources.tsx | 2 +- .../components/+events/kube-event-details.tsx | 2 +- .../+namespaces/namespace-details.tsx | 4 +- .../components/+namespaces/namespace.store.ts | 2 +- .../components/+nodes/node-details.tsx | 4 +- .../add-role-binding-dialog.tsx | 2 +- .../+workloads-cronjobs/cronjob-details.tsx | 4 +- .../daemonset-details.tsx | 4 +- .../deployment-details.tsx | 4 +- .../+workloads-jobs/job-details.tsx | 4 +- .../replicaset-details.tsx | 4 +- .../statefulset-details.tsx | 4 +- src/renderer/components/app.tsx | 9 +++- .../components/dock/upgrade-chart.store.ts | 2 +- .../item-object-list/item-list-layout.tsx | 2 +- src/renderer/components/layout/sidebar.tsx | 4 +- src/renderer/kube-object.store.ts | 15 ++++-- 19 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 8adf58676f..849f93f56c 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -5,11 +5,10 @@ import type { Cluster } from "../../main/cluster"; import type { IKubeWatchEvent, IKubeWatchEventStreamEnd, IWatchRoutePayload } from "../../main/routes/watch-route"; import type { KubeObject } from "./kube-object"; import type { KubeObjectStore } from "../kube-object.store"; -import type { NamespaceStore } from "../components/+namespaces/namespace.store"; import plimit from "p-limit"; import debounce from "lodash/debounce"; -import { comparer, computed, observable, reaction } from "mobx"; +import { autorun, comparer, computed, observable, reaction } from "mobx"; import { autobind, EventEmitter } from "../utils"; import { ensureObjectSelfLink, KubeApi, parseKubeApi } from "./kube-api"; import { KubeJsonApiData, KubeJsonApiError } from "./kube-json-api"; @@ -43,50 +42,49 @@ export interface IKubeWatchLog { @autobind() export class KubeWatchApi { - private cluster: Cluster; - private namespaceStore: NamespaceStore; - private requestId = 0; - private isConnected = false; private reader: ReadableStreamReader; - private subscribers = observable.map(); - - // events public onMessage = new EventEmitter<[IKubeWatchMessage]>(); + @observable.ref private cluster: Cluster; + @observable.ref private namespaces: string[] = []; + @observable subscribers = observable.map(); + @observable isConnected = false; + + @computed get isReady(): boolean { + return Boolean(this.cluster && this.namespaces); + } + @computed get isActive(): boolean { return this.apis.length > 0; } @computed get apis(): string[] { - const { cluster, namespaceStore } = this; - const activeApis = Array.from(this.subscribers.keys()); + if (!this.isReady) { + return []; + } - return activeApis.map(api => { - if (!cluster.isAllowedResource(api.kind)) { + return Array.from(this.subscribers.keys()).map(api => { + if (!this.isAllowedApi(api)) { return []; } if (api.isNamespaced) { - return namespaceStore.getContextNamespaces().map(namespace => api.getWatchUrl(namespace)); + return this.namespaces.map(namespace => api.getWatchUrl(namespace)); } else { return api.getWatchUrl(); } }).flat(); } - constructor() { - this.init(); - } - - private async init() { - const { getHostedCluster } = await import("../../common/cluster-store"); - const { namespaceStore } = await import("../components/+namespaces/namespace.store"); - - await namespaceStore.whenReady; - - this.cluster = getHostedCluster(); - this.namespaceStore = namespaceStore; + async init({ getCluster, getNamespaces }: { + getCluster: () => Cluster, + getNamespaces: () => string[], + }): Promise { + autorun(() => { + this.cluster = getCluster(); + this.namespaces = getNamespaces(); + }); this.bindAutoConnect(); } @@ -108,7 +106,7 @@ export class KubeWatchApi { } isAllowedApi(api: KubeApi): boolean { - return !!this?.cluster.isAllowedResource(api.kind); + return Boolean(this?.cluster.isAllowedResource(api.kind)); } subscribeApi(api: KubeApi | KubeApi[]): () => void { @@ -147,7 +145,7 @@ export class KubeWatchApi { preloading.push(limitRequests(async () => { if (cacheLoading && store.isLoaded) return; // skip - return store.loadAll(); + return store.loadAll(this.namespaces); })); } } diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 6f7ed39fed..0ca6f45b39 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -58,11 +58,11 @@ export class ReleaseStore extends ItemStore { } @action - async loadAll() { + async loadAll(namespaces = namespaceStore.allowedNamespaces) { this.isLoading = true; try { - const items = await this.loadItems(namespaceStore.getContextNamespaces()); + const items = await this.loadItems(namespaces); this.items.replace(this.sortItems(items)); this.isLoaded = true; @@ -73,6 +73,10 @@ export class ReleaseStore extends ItemStore { } } + async loadSelectedNamespaces(): Promise { + return this.loadAll(namespaceStore.getContextNamespaces()); + } + async loadItems(namespaces: string[]) { return Promise .all(namespaces.map(namespace => helmReleasesApi.list(namespace))) @@ -82,7 +86,7 @@ export class ReleaseStore extends ItemStore { async create(payload: IReleaseCreatePayload) { const response = await helmReleasesApi.create(payload); - if (this.isLoaded) this.loadAll(); + if (this.isLoaded) this.loadSelectedNamespaces(); return response; } @@ -90,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.loadAll(); + if (this.isLoaded) this.loadSelectedNamespaces(); return response; } @@ -98,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.loadAll(); + if (this.isLoaded) this.loadSelectedNamespaces(); return response; } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index b9008b410d..2bae92b8d4 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.loadAll(); + store.loadSelectedNamespaces(); } }) ]); diff --git a/src/renderer/components/+events/kube-event-details.tsx b/src/renderer/components/+events/kube-event-details.tsx index 34b16103f0..60821d416d 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.loadAll(); + eventStore.loadSelectedNamespaces(); } render() { diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index 5dfa93cea7..e7397b6a5e 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.loadAll(); - limitRangeStore.loadAll(); + resourceQuotaStore.loadSelectedNamespaces(); + limitRangeStore.loadSelectedNamespaces(); } render() { diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index 63bb7525de..2b234a0cc7 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -73,7 +73,7 @@ export class NamespaceStore extends KubeObjectStore { } private autoLoadAllowedNamespaces(): IReactionDisposer { - return reaction(() => this.allowedNamespaces, () => this.loadAll(), { + return reaction(() => this.allowedNamespaces, namespaces => this.loadAll(namespaces), { fireImmediately: true, equals: comparer.shallow, }); diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index 824affafee..d4208c4545 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -29,9 +29,7 @@ export class NodeDetails extends React.Component { }); async componentDidMount() { - if (!podsStore.isLoaded) { - podsStore.loadAll(); - } + podsStore.loadSelectedNamespaces(); } 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 ab06126bd2..808cef90d6 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.loadAll())); + await Promise.all(stores.map(store => store.loadSelectedNamespaces())); this.isLoading = false; } diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx index 6fd04ffe7e..4daff4abed 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx @@ -20,9 +20,7 @@ interface Props extends KubeObjectDetailsProps { @observer export class CronJobDetails extends React.Component { async componentDidMount() { - if (!jobStore.isLoaded) { - jobStore.loadAll(); - } + jobStore.loadSelectedNamespaces(); } render() { diff --git a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx index 44ccbaac56..ab3269ede5 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx @@ -30,9 +30,7 @@ export class DaemonSetDetails extends React.Component { }); componentDidMount() { - if (!podsStore.isLoaded) { - podsStore.loadAll(); - } + podsStore.loadSelectedNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index 26cd4c0b23..e22137ea67 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -31,9 +31,7 @@ export class DeploymentDetails extends React.Component { }); componentDidMount() { - if (!podsStore.isLoaded) { - podsStore.loadAll(); - } + podsStore.loadSelectedNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/+workloads-jobs/job-details.tsx b/src/renderer/components/+workloads-jobs/job-details.tsx index dfa16fe760..4ce4a9bc61 100644 --- a/src/renderer/components/+workloads-jobs/job-details.tsx +++ b/src/renderer/components/+workloads-jobs/job-details.tsx @@ -25,9 +25,7 @@ interface Props extends KubeObjectDetailsProps { @observer export class JobDetails extends React.Component { async componentDidMount() { - if (!podsStore.isLoaded) { - podsStore.loadAll(); - } + podsStore.loadSelectedNamespaces(); } render() { diff --git a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx index 8c28d81a83..f427d78e9d 100644 --- a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx +++ b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx @@ -29,9 +29,7 @@ export class ReplicaSetDetails extends React.Component { }); async componentDidMount() { - if (!podsStore.isLoaded) { - podsStore.loadAll(); - } + podsStore.loadSelectedNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx index d30633ff32..780572eb96 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx @@ -30,9 +30,7 @@ export class StatefulSetDetails extends React.Component { }); componentDidMount() { - if (!podsStore.isLoaded) { - podsStore.loadAll(); - } + podsStore.loadSelectedNamespaces(); } componentWillUnmount() { diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 2b36bf0057..2236b3d6be 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { computed, observable, reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { Redirect, Route, Router, Switch } from "react-router"; import { history } from "../navigation"; @@ -42,7 +43,7 @@ import { ClusterPageMenuRegistration, clusterPageMenuRegistry } from "../../exte import { TabLayout, TabLayoutRoute } from "./layout/tab-layout"; import { StatefulSetScaleDialog } from "./+workloads-statefulsets/statefulset-scale-dialog"; import { eventStore } from "./+events/event.store"; -import { computed, reaction, observable } from "mobx"; +import { namespaceStore } from "./+namespaces/namespace.store"; import { nodesStore } from "./+nodes/nodes.store"; import { podsStore } from "./+workloads-pods/pods.store"; import { kubeWatchApi } from "../api/kube-watch-api"; @@ -74,6 +75,12 @@ export class App extends React.Component { window.location.reload(); }); whatInput.ask(); // Start to monitor user input device + + await namespaceStore.whenReady; + await kubeWatchApi.init({ + getCluster: getHostedCluster, + getNamespaces: namespaceStore.getContextNamespaces, + }); } componentDidMount() { diff --git a/src/renderer/components/dock/upgrade-chart.store.ts b/src/renderer/components/dock/upgrade-chart.store.ts index bc7445e29d..f609420d9d 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.loadAll(), + !releaseStore.isLoaded && releaseStore.loadSelectedNamespaces(), !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 b13d496064..ac0d2ea635 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,7 @@ export class ItemListLayout extends React.Component { const { store, dependentStores } = this.props; const stores = Array.from(new Set([store, ...dependentStores])); - stores.forEach(store => store.loadAll()); + stores.forEach(store => store.loadAll(namespaceStore.getContextNamespaces())); } private filterCallbacks: { [type: string]: ItemsFilter } = { diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index b44dd4a759..20c401ab4f 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -40,9 +40,7 @@ interface Props { @observer export class Sidebar extends React.Component { async componentDidMount() { - if (!crdStore.isLoaded && isAllowedResource("customresourcedefinitions")) { - crdStore.loadAll(); - } + crdStore.loadSelectedNamespaces(); } renderCustomResources() { diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index 760ebd3335..d56e6bd912 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -106,17 +106,18 @@ export abstract class KubeObjectStore extends ItemSt } @action - async loadAll({ namespaces: contextNamespaces }: { namespaces?: string[] } = {}) { + async loadAll(namespaces: string[] = []): Promise { this.isLoading = true; try { - if (!contextNamespaces) { + if (!namespaces.length) { const { namespaceStore } = await import("./components/+namespaces/namespace.store"); - contextNamespaces = namespaceStore.getContextNamespaces(); + // load all available namespaces by default + namespaces.push(...namespaceStore.allowedNamespaces); } - let items = await this.loadItems({ namespaces: contextNamespaces, api: this.api }); + let items = await this.loadItems({ namespaces, api: this.api }); items = this.filterItemsOnLoad(items); items = this.sortItems(items); @@ -131,6 +132,12 @@ export abstract class KubeObjectStore extends ItemSt } } + async loadSelectedNamespaces(): Promise { + const { namespaceStore } = await import("./components/+namespaces/namespace.store"); + + return this.loadAll(namespaceStore.getContextNamespaces()); + } + protected resetOnError(error: any) { if (error) this.reset(); }