mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Detach NamespaceStore from KubeWatchApi, proper KubeObjectStore.loadAll (rebase of #2033)
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
21adda2c64
commit
bd9e44109a
@ -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<string>;
|
||||
private subscribers = observable.map<KubeApi, number>();
|
||||
|
||||
// events
|
||||
public onMessage = new EventEmitter<[IKubeWatchMessage]>();
|
||||
|
||||
@observable.ref private cluster: Cluster;
|
||||
@observable.ref private namespaces: string[] = [];
|
||||
@observable subscribers = observable.map<KubeApi, number>();
|
||||
@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<void> {
|
||||
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);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,11 +58,11 @@ export class ReleaseStore extends ItemStore<HelmRelease> {
|
||||
}
|
||||
|
||||
@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<HelmRelease> {
|
||||
}
|
||||
}
|
||||
|
||||
async loadSelectedNamespaces(): Promise<void> {
|
||||
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<HelmRelease> {
|
||||
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<HelmRelease> {
|
||||
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<HelmRelease> {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ export class CrdResources extends React.Component<Props> {
|
||||
const { store } = this;
|
||||
|
||||
if (store && !store.isLoading && !store.isLoaded) {
|
||||
store.loadAll();
|
||||
store.loadSelectedNamespaces();
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
@ -14,7 +14,7 @@ export interface KubeEventDetailsProps {
|
||||
@observer
|
||||
export class KubeEventDetails extends React.Component<KubeEventDetailsProps> {
|
||||
async componentDidMount() {
|
||||
eventStore.loadAll();
|
||||
eventStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@ -32,8 +32,8 @@ export class NamespaceDetails extends React.Component<Props> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
resourceQuotaStore.loadAll();
|
||||
limitRangeStore.loadAll();
|
||||
resourceQuotaStore.loadSelectedNamespaces();
|
||||
limitRangeStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@ -73,7 +73,7 @@ export class NamespaceStore extends KubeObjectStore<Namespace> {
|
||||
}
|
||||
|
||||
private autoLoadAllowedNamespaces(): IReactionDisposer {
|
||||
return reaction(() => this.allowedNamespaces, () => this.loadAll(), {
|
||||
return reaction(() => this.allowedNamespaces, namespaces => this.loadAll(namespaces), {
|
||||
fireImmediately: true,
|
||||
equals: comparer.shallow,
|
||||
});
|
||||
|
||||
@ -29,9 +29,7 @@ export class NodeDetails extends React.Component<Props> {
|
||||
});
|
||||
|
||||
async componentDidMount() {
|
||||
if (!podsStore.isLoaded) {
|
||||
podsStore.loadAll();
|
||||
}
|
||||
podsStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
@ -80,7 +80,7 @@ export class AddRoleBindingDialog extends React.Component<Props> {
|
||||
];
|
||||
|
||||
this.isLoading = true;
|
||||
await Promise.all(stores.map(store => store.loadAll()));
|
||||
await Promise.all(stores.map(store => store.loadSelectedNamespaces()));
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
|
||||
@ -20,9 +20,7 @@ interface Props extends KubeObjectDetailsProps<CronJob> {
|
||||
@observer
|
||||
export class CronJobDetails extends React.Component<Props> {
|
||||
async componentDidMount() {
|
||||
if (!jobStore.isLoaded) {
|
||||
jobStore.loadAll();
|
||||
}
|
||||
jobStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@ -30,9 +30,7 @@ export class DaemonSetDetails extends React.Component<Props> {
|
||||
});
|
||||
|
||||
componentDidMount() {
|
||||
if (!podsStore.isLoaded) {
|
||||
podsStore.loadAll();
|
||||
}
|
||||
podsStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
@ -31,9 +31,7 @@ export class DeploymentDetails extends React.Component<Props> {
|
||||
});
|
||||
|
||||
componentDidMount() {
|
||||
if (!podsStore.isLoaded) {
|
||||
podsStore.loadAll();
|
||||
}
|
||||
podsStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
@ -25,9 +25,7 @@ interface Props extends KubeObjectDetailsProps<Job> {
|
||||
@observer
|
||||
export class JobDetails extends React.Component<Props> {
|
||||
async componentDidMount() {
|
||||
if (!podsStore.isLoaded) {
|
||||
podsStore.loadAll();
|
||||
}
|
||||
podsStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@ -29,9 +29,7 @@ export class ReplicaSetDetails extends React.Component<Props> {
|
||||
});
|
||||
|
||||
async componentDidMount() {
|
||||
if (!podsStore.isLoaded) {
|
||||
podsStore.loadAll();
|
||||
}
|
||||
podsStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
@ -30,9 +30,7 @@ export class StatefulSetDetails extends React.Component<Props> {
|
||||
});
|
||||
|
||||
componentDidMount() {
|
||||
if (!podsStore.isLoaded) {
|
||||
podsStore.loadAll();
|
||||
}
|
||||
podsStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -80,7 +80,7 @@ export class UpgradeChartStore extends DockTabStore<IChartUpgradeData> {
|
||||
const values = this.values.getData(tabId);
|
||||
|
||||
await Promise.all([
|
||||
!releaseStore.isLoaded && releaseStore.loadAll(),
|
||||
!releaseStore.isLoaded && releaseStore.loadSelectedNamespaces(),
|
||||
!values && this.loadValues(tabId)
|
||||
]);
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
||||
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 } = {
|
||||
|
||||
@ -40,9 +40,7 @@ interface Props {
|
||||
@observer
|
||||
export class Sidebar extends React.Component<Props> {
|
||||
async componentDidMount() {
|
||||
if (!crdStore.isLoaded && isAllowedResource("customresourcedefinitions")) {
|
||||
crdStore.loadAll();
|
||||
}
|
||||
crdStore.loadSelectedNamespaces();
|
||||
}
|
||||
|
||||
renderCustomResources() {
|
||||
|
||||
@ -106,17 +106,18 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
|
||||
}
|
||||
|
||||
@action
|
||||
async loadAll({ namespaces: contextNamespaces }: { namespaces?: string[] } = {}) {
|
||||
async loadAll(namespaces: string[] = []): Promise<void> {
|
||||
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<T extends KubeObject = any> extends ItemSt
|
||||
}
|
||||
}
|
||||
|
||||
async loadSelectedNamespaces(): Promise<void> {
|
||||
const { namespaceStore } = await import("./components/+namespaces/namespace.store");
|
||||
|
||||
return this.loadAll(namespaceStore.getContextNamespaces());
|
||||
}
|
||||
|
||||
protected resetOnError(error: any) {
|
||||
if (error) this.reset();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user