mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
refactoring & fixes
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
36d54c64fc
commit
4240d3afbc
@ -8,7 +8,7 @@ import type { ClusterContext } from "../components/context";
|
|||||||
|
|
||||||
import plimit from "p-limit";
|
import plimit from "p-limit";
|
||||||
import debounce from "lodash/debounce";
|
import debounce from "lodash/debounce";
|
||||||
import { comparer, computed, IReactionDisposer, observable, reaction, when } from "mobx";
|
import { comparer, computed, IReactionDisposer, observable, reaction, toJS, when } from "mobx";
|
||||||
import { autobind, EventEmitter, noop } from "../utils";
|
import { autobind, EventEmitter, noop } from "../utils";
|
||||||
import { ensureObjectSelfLink, KubeApi, parseKubeApi } from "./kube-api";
|
import { ensureObjectSelfLink, KubeApi, parseKubeApi } from "./kube-api";
|
||||||
import { KubeJsonApiData, KubeJsonApiError } from "./kube-json-api";
|
import { KubeJsonApiData, KubeJsonApiError } from "./kube-json-api";
|
||||||
@ -26,7 +26,7 @@ export interface IKubeWatchMessage<T extends KubeObject = any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IKubeWatchSubscribeStoreOptions {
|
export interface IKubeWatchSubscribeStoreOptions {
|
||||||
namespaces?: string[]; // todo: support custom namespaces to subscribe
|
namespaces?: string[]; // default: all accessible namespaces
|
||||||
preload?: boolean; // preload store items, default: true
|
preload?: boolean; // preload store items, default: true
|
||||||
waitUntilLoaded?: boolean; // subscribe only after loading all stores, default: true
|
waitUntilLoaded?: boolean; // subscribe only after loading all stores, default: true
|
||||||
loadOnce?: boolean; // check store.isLoaded to skip loading if done already, default: false
|
loadOnce?: boolean; // check store.isLoaded to skip loading if done already, default: false
|
||||||
@ -134,9 +134,7 @@ export class KubeWatchApi {
|
|||||||
preloading.push(limitRequests(async () => {
|
preloading.push(limitRequests(async () => {
|
||||||
if (store.isLoaded && opts.loadOnce) return; // skip
|
if (store.isLoaded && opts.loadOnce) return; // skip
|
||||||
|
|
||||||
return store.loadAll({
|
return store.loadAll({ namespaces: opts.namespaces });
|
||||||
namespaces: opts.namespaces ?? this.context?.contextNamespaces,
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,13 +144,14 @@ export class KubeWatchApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribeStores(stores: KubeObjectStore[], options: IKubeWatchSubscribeStoreOptions = {}): () => void {
|
subscribeStores(stores: KubeObjectStore[], opts: IKubeWatchSubscribeStoreOptions = {}): () => void {
|
||||||
const { preload = true, waitUntilLoaded = true, loadOnce = false } = options;
|
const { preload = true, waitUntilLoaded = true, loadOnce = false, } = opts;
|
||||||
const apis = new Set(stores.map(store => store.getSubscribeApis()).flat());
|
const apis = new Set(stores.map(store => store.getSubscribeApis()).flat());
|
||||||
const unsubscribeList: (() => void)[] = [];
|
const unsubscribeList: Function[] = [];
|
||||||
let isUnsubscribed = false;
|
let isUnsubscribed = false;
|
||||||
|
|
||||||
const load = (namespaces?: string[]) => this.preloadStores(stores, { namespaces, loadOnce });
|
const namespaces = opts.namespaces ?? this.context?.allNamespaces ?? [];
|
||||||
|
const load = () => this.preloadStores(stores, { namespaces, loadOnce });
|
||||||
let preloading = preload && load();
|
let preloading = preload && load();
|
||||||
let cancelReloading: IReactionDisposer = noop;
|
let cancelReloading: IReactionDisposer = noop;
|
||||||
|
|
||||||
@ -166,17 +165,17 @@ export class KubeWatchApi {
|
|||||||
preloading.loading.then(subscribe, error => {
|
preloading.loading.then(subscribe, error => {
|
||||||
this.log({
|
this.log({
|
||||||
message: new Error("Loading stores has failed"),
|
message: new Error("Loading stores has failed"),
|
||||||
meta: { stores, error, options },
|
meta: { stores, error, options: opts },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
subscribe();
|
subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
// partial reload only selected namespaces
|
// reload stores for requested namespaces
|
||||||
cancelReloading = reaction(() => this.context.contextNamespaces, namespaces => {
|
cancelReloading = reaction(() => toJS(namespaces), () => {
|
||||||
preloading?.cancelLoading();
|
preloading?.cancelLoading();
|
||||||
preloading = load(namespaces);
|
preloading = load();
|
||||||
}, {
|
}, {
|
||||||
equals: comparer.shallow,
|
equals: comparer.shallow,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { cronJobStore } from "../+workloads-cronjobs/cronjob.store";
|
|||||||
import { Events } from "../+events";
|
import { Events } from "../+events";
|
||||||
import { isAllowedResource } from "../../../common/rbac";
|
import { isAllowedResource } from "../../../common/rbac";
|
||||||
import { kubeWatchApi } from "../../api/kube-watch-api";
|
import { kubeWatchApi } from "../../api/kube-watch-api";
|
||||||
|
import { clusterContext } from "../context";
|
||||||
|
|
||||||
interface Props extends RouteComponentProps<IWorkloadsOverviewRouteParams> {
|
interface Props extends RouteComponentProps<IWorkloadsOverviewRouteParams> {
|
||||||
}
|
}
|
||||||
@ -29,6 +30,7 @@ export class WorkloadsOverview extends React.Component<Props> {
|
|||||||
jobStore, cronJobStore, eventStore,
|
jobStore, cronJobStore, eventStore,
|
||||||
], {
|
], {
|
||||||
preload: true,
|
preload: true,
|
||||||
|
namespaces: clusterContext.contextNamespaces,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@ interface IHeaderPlaceholders {
|
|||||||
export interface ItemListLayoutProps<T extends ItemObject = ItemObject> {
|
export interface ItemListLayoutProps<T extends ItemObject = ItemObject> {
|
||||||
tableId?: string;
|
tableId?: string;
|
||||||
className: IClassName;
|
className: IClassName;
|
||||||
|
items?: T[];
|
||||||
store: ItemStore<T>;
|
store: ItemStore<T>;
|
||||||
dependentStores?: ItemStore[];
|
dependentStores?: ItemStore[];
|
||||||
preloadStores?: boolean;
|
preloadStores?: boolean;
|
||||||
@ -218,7 +219,8 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.applyFilters(filterItems, allItems);
|
const items = this.props.items ?? allItems;
|
||||||
|
return this.applyFilters(filterItems, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { KubeObjectStore } from "../../kube-object.store";
|
|||||||
import { KubeObjectMenu } from "./kube-object-menu";
|
import { KubeObjectMenu } from "./kube-object-menu";
|
||||||
import { kubeSelectedUrlParam, showDetails } from "./kube-object-details";
|
import { kubeSelectedUrlParam, showDetails } from "./kube-object-details";
|
||||||
import { kubeWatchApi } from "../../api/kube-watch-api";
|
import { kubeWatchApi } from "../../api/kube-watch-api";
|
||||||
|
import { clusterContext } from "../context";
|
||||||
|
|
||||||
export interface KubeObjectListLayoutProps extends ItemListLayoutProps {
|
export interface KubeObjectListLayoutProps extends ItemListLayoutProps {
|
||||||
store: KubeObjectStore;
|
store: KubeObjectStore;
|
||||||
@ -26,7 +27,8 @@ export class KubeObjectListLayout extends React.Component<KubeObjectListLayoutPr
|
|||||||
|
|
||||||
disposeOnUnmount(this, [
|
disposeOnUnmount(this, [
|
||||||
kubeWatchApi.subscribeStores(stores, {
|
kubeWatchApi.subscribeStores(stores, {
|
||||||
preload: true
|
preload: true,
|
||||||
|
namespaces: clusterContext.contextNamespaces,
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -40,12 +42,14 @@ export class KubeObjectListLayout extends React.Component<KubeObjectListLayoutPr
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const items = this.props.store.contextItems;
|
||||||
const { className, ...layoutProps } = this.props;
|
const { className, ...layoutProps } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemListLayout
|
<ItemListLayout
|
||||||
{...layoutProps}
|
{...layoutProps}
|
||||||
className={cssNames("KubeObjectListLayout", className)}
|
className={cssNames("KubeObjectListLayout", className)}
|
||||||
|
items={items}
|
||||||
preloadStores={false} // loading handled in kubeWatchApi.subscribeStores()
|
preloadStores={false} // loading handled in kubeWatchApi.subscribeStores()
|
||||||
detailsItem={this.selectedItem}
|
detailsItem={this.selectedItem}
|
||||||
onDetails={this.onDetails}
|
onDetails={this.onDetails}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { ClusterContext } from "./components/context";
|
import type { ClusterContext } from "./components/context";
|
||||||
|
|
||||||
import { action, observable, reaction, when } from "mobx";
|
import { action, computed, observable, reaction, when } from "mobx";
|
||||||
import { autobind } from "./utils";
|
import { autobind } from "./utils";
|
||||||
import { KubeObject } from "./api/kube-object";
|
import { KubeObject } from "./api/kube-object";
|
||||||
import { IKubeWatchEvent, IKubeWatchMessage, kubeWatchApi } from "./api/kube-watch-api";
|
import { IKubeWatchEvent, IKubeWatchMessage, kubeWatchApi } from "./api/kube-watch-api";
|
||||||
@ -24,13 +24,22 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
|
|||||||
|
|
||||||
contextReady = when(() => Boolean(this.context));
|
contextReady = when(() => Boolean(this.context));
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.bindWatchEventsUpdater();
|
||||||
|
}
|
||||||
|
|
||||||
get context(): ClusterContext {
|
get context(): ClusterContext {
|
||||||
return KubeObjectStore.defaultContext;
|
return KubeObjectStore.defaultContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
@computed get contextItems(): T[] {
|
||||||
super();
|
const namespaces = this.context?.contextNamespaces ?? [];
|
||||||
this.bindWatchEventsUpdater();
|
|
||||||
|
return this.items.filter(item => {
|
||||||
|
const itemNamespace = item.getNs();
|
||||||
|
return !itemNamespace /* cluster-wide */ || namespaces.includes(itemNamespace);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get query(): IKubeApiQueryParams {
|
get query(): IKubeApiQueryParams {
|
||||||
@ -107,21 +116,22 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async loadAll({ namespaces = [], merge = true } = {}): Promise<void | T[]> {
|
async loadAll(options: { namespaces?: string[], merge?: boolean } = {}): Promise<void | T[]> {
|
||||||
await this.contextReady;
|
await this.contextReady;
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!namespaces.length) {
|
const {
|
||||||
namespaces = this.context.allNamespaces; // load all available namespaces by default
|
namespaces = this.context.allNamespaces, // load all namespaces by default
|
||||||
}
|
merge = true, // merge loaded items or return as result
|
||||||
|
} = options;
|
||||||
|
|
||||||
const items = await this.loadItems({ namespaces, api: this.api });
|
const items = await this.loadItems({ namespaces, api: this.api });
|
||||||
|
|
||||||
this.isLoaded = true;
|
this.isLoaded = true;
|
||||||
|
|
||||||
if (merge) {
|
if (merge) {
|
||||||
this.mergeItems(items);
|
this.mergeItems(items, { replace: false });
|
||||||
} else {
|
} else {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
@ -134,7 +144,7 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
reloadAll(opts: { namespaces?: string[], merge?: boolean, force?: boolean } = {}) {
|
reloadAll(opts: { force?: boolean, namespaces?: string[], merge?: boolean } = {}) {
|
||||||
const { force = false, ...loadingOptions } = opts;
|
const { force = false, ...loadingOptions } = opts;
|
||||||
|
|
||||||
if (this.isLoading || (this.isLoaded && !force)) {
|
if (this.isLoading || (this.isLoaded && !force)) {
|
||||||
@ -145,7 +155,7 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
mergeItems(partialItems: T[], { replace = true, updateStore = true, sort = true, filter = true } = {}): T[] {
|
mergeItems(partialItems: T[], { replace = false, updateStore = true, sort = true, filter = true } = {}): T[] {
|
||||||
let items = partialItems;
|
let items = partialItems;
|
||||||
|
|
||||||
// update existing items
|
// update existing items
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user