From 2208438ec81099cdfc8a18e2b7fd1d24f6d32a2d Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 21 May 2021 10:17:00 -0400 Subject: [PATCH] Improve Table typing and remove annotations on callbacks Signed-off-by: Sebastian Malton --- .../api/__tests__/api-manager.test.ts | 4 +- src/renderer/api/__tests__/crd.test.ts | 10 ++-- src/renderer/api/__tests__/kube-api.test.ts | 15 +++-- src/renderer/api/api-manager.ts | 27 +++++---- .../api/endpoints/resource-applier.api.ts | 4 +- src/renderer/api/kube-api.ts | 24 ++++---- src/renderer/api/kube-object.ts | 16 ++--- src/renderer/api/kube-watch-api.ts | 9 +-- .../+apps-helm-charts/helm-charts.tsx | 14 ++--- .../components/+apps-releases/releases.tsx | 28 ++++----- src/renderer/components/+catalog/catalog.tsx | 26 ++++---- .../components/+config-autoscalers/hpa.tsx | 16 ++--- .../+config-limit-ranges/limit-ranges.tsx | 15 +++-- .../components/+config-maps/config-maps.tsx | 15 +++-- .../pod-disruption-budgets.tsx | 18 +++--- .../resource-quotas.tsx | 13 ++-- .../+config-secrets/add-secret-dialog.tsx | 4 +- .../components/+config-secrets/secrets.tsx | 19 +++--- .../components/+custom-resources/crd-list.tsx | 13 ++-- .../+custom-resources/crd-resource.store.ts | 6 +- .../+custom-resources/crd-resources.tsx | 16 ++--- .../components/+custom-resources/crd.store.ts | 9 ++- src/renderer/components/+events/events.tsx | 40 ++++++------- .../components/+namespaces/namespace.store.ts | 2 +- .../components/+namespaces/namespaces.tsx | 18 +++--- .../+network-endpoints/endpoints.tsx | 13 ++-- .../+network-ingresses/ingresses.tsx | 15 +++-- .../+network-policies/network-policies.tsx | 11 ++-- .../components/+network-services/services.tsx | 25 ++++---- src/renderer/components/+nodes/nodes.tsx | 28 ++++----- .../pod-security-policies.tsx | 17 +++--- .../+storage-classes/storage-classes.tsx | 15 +++-- .../+storage-volume-claims/volume-claims.tsx | 21 ++++--- .../components/+storage-volumes/volumes.tsx | 17 +++--- .../+cluster-role-bindings/view.tsx | 13 ++-- .../+user-management/+cluster-roles/view.tsx | 9 ++- .../+user-management/+role-bindings/view.tsx | 15 +++-- .../+user-management/+roles/view.tsx | 11 ++-- .../+service-accounts/view.tsx | 10 ++-- .../cronjob-trigger-dialog.tsx | 4 +- .../+workloads-cronjobs/cronjobs.tsx | 18 +++--- .../+workloads-daemonsets/daemonsets.tsx | 14 ++--- .../+workloads-deployments/deployments.tsx | 20 +++---- .../components/+workloads-jobs/jobs.tsx | 13 ++-- .../+workloads-overview/overview-statuses.tsx | 7 ++- .../+workloads-pods/pod-tolerations.tsx | 19 +++--- .../components/+workloads-pods/pods.tsx | 28 ++++----- .../+workloads-replicasets/replicasets.tsx | 16 ++--- .../+workloads-statefulsets/statefulsets.tsx | 16 +++-- .../components/+workloads/workloads.stores.ts | 19 +++--- .../components/dock/edit-resource.store.ts | 2 +- .../item-object-list/item-list-layout.tsx | 59 ++++++++++--------- .../kube-object/kube-object-details.tsx | 10 +--- .../kube-object/kube-object-list-layout.tsx | 14 ++--- .../kube-object/kube-object-meta.tsx | 8 +-- src/renderer/components/table/table.tsx | 35 +++++++---- .../kube-object-detail-registry.tsx | 10 +++- src/renderer/item.store.ts | 42 ++++++------- src/renderer/kube-object.store.ts | 14 ++--- 59 files changed, 487 insertions(+), 482 deletions(-) diff --git a/src/renderer/api/__tests__/api-manager.test.ts b/src/renderer/api/__tests__/api-manager.test.ts index 8c7beb12c9..83034d20b6 100644 --- a/src/renderer/api/__tests__/api-manager.test.ts +++ b/src/renderer/api/__tests__/api-manager.test.ts @@ -22,8 +22,9 @@ import { ingressStore } from "../../components/+network-ingresses/ingress.store"; import { apiManager } from "../api-manager"; import { KubeApi } from "../kube-api"; +import { KubeObject } from "../kube-object"; -class TestApi extends KubeApi { +class TestApi extends KubeApi { protected async checkPreferredVersion() { return; @@ -36,6 +37,7 @@ describe("ApiManager", () => { const apiBase = "apis/v1/foo"; const fallbackApiBase = "/apis/extensions/v1beta1/foo"; const kubeApi = new TestApi({ + objectConstructor: KubeObject, apiBase, fallbackApiBases: [fallbackApiBase], checkPreferredVersion: true, diff --git a/src/renderer/api/__tests__/crd.test.ts b/src/renderer/api/__tests__/crd.test.ts index af7db4280c..459a7f67d9 100644 --- a/src/renderer/api/__tests__/crd.test.ts +++ b/src/renderer/api/__tests__/crd.test.ts @@ -20,7 +20,7 @@ */ import { CustomResourceDefinition } from "../endpoints"; -import type { IKubeObjectMetadata } from "../kube-object"; +import type { KubeObjectMetadata } from "../kube-object"; describe("Crds", () => { describe("getVersion", () => { @@ -28,7 +28,7 @@ describe("Crds", () => { const crd = new CustomResourceDefinition({ apiVersion: "foo", kind: "CustomResourceDefinition", - metadata: {} as IKubeObjectMetadata, + metadata: {} as KubeObjectMetadata, }); crd.spec = { @@ -48,7 +48,7 @@ describe("Crds", () => { const crd = new CustomResourceDefinition({ apiVersion: "foo", kind: "CustomResourceDefinition", - metadata: {} as IKubeObjectMetadata, + metadata: {} as KubeObjectMetadata, }); crd.spec = { @@ -73,7 +73,7 @@ describe("Crds", () => { const crd = new CustomResourceDefinition({ apiVersion: "foo", kind: "CustomResourceDefinition", - metadata: {} as IKubeObjectMetadata, + metadata: {} as KubeObjectMetadata, }); crd.spec = { @@ -99,7 +99,7 @@ describe("Crds", () => { const crd = new CustomResourceDefinition({ apiVersion: "foo", kind: "CustomResourceDefinition", - metadata: {} as IKubeObjectMetadata, + metadata: {} as KubeObjectMetadata, }); crd.spec = { diff --git a/src/renderer/api/__tests__/kube-api.test.ts b/src/renderer/api/__tests__/kube-api.test.ts index c7415cba73..1eb0199f89 100644 --- a/src/renderer/api/__tests__/kube-api.test.ts +++ b/src/renderer/api/__tests__/kube-api.test.ts @@ -20,6 +20,7 @@ */ import { KubeApi } from "../kube-api"; +import { KubeObject } from "../kube-object"; describe("KubeApi", () => { it("uses url from apiBase if apiBase contains the resource", async () => { @@ -29,7 +30,7 @@ describe("KubeApi", () => { body: JSON.stringify({ resources: [{ name: "ingresses" - }] as any [] + }] as any[] }) }; } else if (request.url === "/api-kube/apis/extensions/v1beta1") { @@ -38,13 +39,13 @@ describe("KubeApi", () => { body: JSON.stringify({ resources: [{ name: "ingresses" - }] as any [] + }] as any[] }) }; } else { return { body: JSON.stringify({ - resources: [] as any [] + resources: [] as any[] }) }; } @@ -53,6 +54,7 @@ describe("KubeApi", () => { const apiBase = "/apis/networking.k8s.io/v1/ingresses"; const fallbackApiBase = "/apis/extensions/v1beta1/ingresses"; const kubeApi = new KubeApi({ + objectConstructor: KubeObject, apiBase, fallbackApiBases: [fallbackApiBase], checkPreferredVersion: true, @@ -68,7 +70,7 @@ describe("KubeApi", () => { if (request.url === "/api-kube/apis/networking.k8s.io/v1") { return { body: JSON.stringify({ - resources: [] as any [] + resources: [] as any[] }) }; } else if (request.url === "/api-kube/apis/extensions/v1beta1") { @@ -76,13 +78,13 @@ describe("KubeApi", () => { body: JSON.stringify({ resources: [{ name: "ingresses" - }] as any [] + }] as any[] }) }; } else { return { body: JSON.stringify({ - resources: [] as any [] + resources: [] as any[] }) }; } @@ -91,6 +93,7 @@ describe("KubeApi", () => { const apiBase = "apis/networking.k8s.io/v1/ingresses"; const fallbackApiBase = "/apis/extensions/v1beta1/ingresses"; const kubeApi = new KubeApi({ + objectConstructor: KubeObject, apiBase, fallbackApiBases: [fallbackApiBase], checkPreferredVersion: true, diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index 9477446386..1e01bd4cfb 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -22,34 +22,35 @@ import type { KubeObjectStore } from "../kube-object.store"; import { action, observable, makeObservable } from "mobx"; -import { autoBind } from "../utils"; +import { autoBind, iter } from "../utils"; import { KubeApi, parseKubeApi } from "./kube-api"; +import type { KubeObject } from "./kube-object"; export class ApiManager { - private apis = observable.map(); - private stores = observable.map(); + private apis = observable.map>(); + private stores = observable.map>(); constructor() { makeObservable(this); autoBind(this); } - getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) { + getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) { if (typeof pathOrCallback === "string") { return this.apis.get(pathOrCallback) || this.apis.get(parseKubeApi(pathOrCallback).apiBase); } - return Array.from(this.apis.values()).find(pathOrCallback ?? (() => true)); + return iter.find(this.apis.values(), pathOrCallback ?? (() => true)); } getApiByKind(kind: string, apiVersion: string) { - return Array.from(this.apis.values()).find((api) => api.kind === kind && api.apiVersionWithGroup === apiVersion); + return iter.find(this.apis.values(), api => api.kind === kind && api.apiVersionWithGroup === apiVersion); } - registerApi(apiBase: string, api: KubeApi) { + registerApi(apiBase: string, api: KubeApi) { if (!this.apis.has(apiBase)) { this.stores.forEach((store) => { - if(store.api === api) { + if (store.api === api) { this.stores.set(apiBase, store); } }); @@ -58,19 +59,19 @@ export class ApiManager { } } - protected resolveApi(api?: string | KubeApi): KubeApi | undefined { + protected resolveApi(api?: string | KubeApi): KubeApi | undefined { if (!api) { return undefined; } if (typeof api === "string") { - return this.getApi(api); + return this.getApi(api) as KubeApi; } return api; } - unregisterApi(api: string | KubeApi) { + unregisterApi(api: string | KubeApi) { if (typeof api === "string") this.apis.delete(api); else { const apis = Array.from(this.apis.entries()); @@ -81,13 +82,13 @@ export class ApiManager { } @action - registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { + registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { apis.forEach(api => { this.stores.set(api.apiBase, store); }); } - getStore(api: string | KubeApi): S { + getStore>(api: string | KubeApi): S | undefined { return this.stores.get(this.resolveApi(api)?.apiBase) as S; } } diff --git a/src/renderer/api/endpoints/resource-applier.api.ts b/src/renderer/api/endpoints/resource-applier.api.ts index 1756977c95..b10c10f7db 100644 --- a/src/renderer/api/endpoints/resource-applier.api.ts +++ b/src/renderer/api/endpoints/resource-applier.api.ts @@ -30,7 +30,7 @@ export const resourceApplierApi = { "kubectl.kubernetes.io/last-applied-configuration" ], - async update(resource: object | string): Promise { + async update(resource: object | string): Promise { if (typeof resource === "string") { resource = jsYaml.safeLoad(resource); } @@ -48,7 +48,7 @@ export const resourceApplierApi = { } }); - return items.length === 1 ? items[0] : items; + return items[0] as K ?? null; }); } }; diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index 21e370a207..20c4672727 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -28,7 +28,7 @@ import logger from "../../main/logger"; import { apiManager } from "./api-manager"; import { apiKube } from "./index"; import { createKubeApiURL, parseKubeApi } from "./kube-api-parse"; -import { IKubeObjectConstructor, KubeObject, KubeStatus } from "./kube-object"; +import { KubeObjectConstructor, KubeObject, KubeStatus } from "./kube-object"; import byline from "byline"; import type { IKubeWatchEvent } from "./kube-watch-api"; import { ReadableWebToNodeStream } from "../utils/readableStream"; @@ -49,7 +49,7 @@ export interface IKubeApiOptions { */ fallbackApiBases?: string[]; - objectConstructor?: IKubeObjectConstructor; + objectConstructor: KubeObjectConstructor; request?: KubeJsonApi; isNamespaced?: boolean; kind?: string; @@ -99,7 +99,7 @@ export interface IKubeApiCluster { } } -export function forCluster(cluster: IKubeApiCluster, kubeClass: IKubeObjectConstructor): KubeApi { +export function forCluster(cluster: IKubeApiCluster, kubeClass: KubeObjectConstructor): KubeApi { const request = new KubeJsonApi({ apiBase: apiKubePrefix, debug: isDevelopment, @@ -115,7 +115,7 @@ export function forCluster(cluster: IKubeApiCluster, kubeC }); } -export function ensureObjectSelfLink(api: KubeApi, object: KubeJsonApiData) { +export function ensureObjectSelfLink(api: KubeApi, object: KubeJsonApiData) { if (!object.metadata.selfLink) { object.metadata.selfLink = createKubeApiURL({ apiPrefix: api.apiPrefix, @@ -127,7 +127,7 @@ export function ensureObjectSelfLink(api: KubeApi, object: KubeJsonApiData) { } } -export type KubeApiWatchCallback = (data: IKubeWatchEvent, error: any) => void; +export type KubeApiWatchCallback = (data: IKubeWatchEvent, error: any) => void; export type KubeApiWatchOptions = { namespace: string; @@ -135,7 +135,7 @@ export type KubeApiWatchOptions = { abortController?: AbortController }; -export class KubeApi { +export class KubeApi { readonly kind: string; readonly apiBase: string; readonly apiPrefix: string; @@ -145,14 +145,14 @@ export class KubeApi { readonly apiResource: string; readonly isNamespaced: boolean; - public objectConstructor: IKubeObjectConstructor; + public objectConstructor: KubeObjectConstructor; protected request: KubeJsonApi; protected resourceVersions = new Map(); protected watchDisposer: () => void; constructor(protected options: IKubeApiOptions) { const { - objectConstructor = KubeObject as IKubeObjectConstructor, + objectConstructor, request = apiKube, kind = options.objectConstructor?.kind, isNamespaced = options.objectConstructor?.namespaced @@ -456,14 +456,14 @@ export class KubeApi { clearTimeout(timedRetry); timedRetry = setTimeout(() => { // we did not get any kubernetes errors so let's retry - this.watch({...opts, namespace, callback}); + this.watch({ ...opts, namespace, callback }); }, 1000); }); }); byline(nodeStream).on("data", (line) => { try { - const event: IKubeWatchEvent = JSON.parse(line); + const event: IKubeWatchEvent = JSON.parse(line); if (event.type === "ERROR" && event.object.kind === "Status") { errorReceived = true; @@ -474,7 +474,7 @@ export class KubeApi { this.modifyWatchEvent(event); callback(event, null); } catch (ignore) { - // ignore parse errors + // ignore parse errors } }); }) @@ -487,7 +487,7 @@ export class KubeApi { return abort; } - protected modifyWatchEvent(event: IKubeWatchEvent) { + protected modifyWatchEvent(event: IKubeWatchEvent) { switch (event.type) { case "ADDED": diff --git a/src/renderer/api/kube-object.ts b/src/renderer/api/kube-object.ts index 024651c4d9..2548cac3aa 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -31,13 +31,13 @@ import { resourceApplierApi } from "./endpoints/resource-applier.api"; import { hasOptionalProperty, hasTypedProperty, isObject, isString, bindPredicate, isTypedArray, isRecord } from "../../common/utils/type-narrowing"; import _ from "lodash"; -export type IKubeObjectConstructor = (new (data: KubeJsonApiData | any) => T) & { +export type KubeObjectConstructor = (new (data: KubeJsonApiData | any) => K) & { kind?: string; namespaced?: boolean; apiBase?: string; }; -export interface IKubeObjectMetadata { +export interface KubeObjectMetadata { uid: string; name: string; namespace?: string; @@ -63,7 +63,7 @@ export interface IKubeObjectMetadata { }[]; } -export interface IKubeStatus { +export interface KubeStatusData { kind: string; apiVersion: string; code: number; @@ -78,7 +78,7 @@ export class KubeStatus { public readonly message: string; public readonly reason: string; - constructor(data: IKubeStatus) { + constructor(data: KubeStatusData) { this.apiVersion = data.apiVersion; this.code = data.code; this.message = data.message || ""; @@ -86,9 +86,9 @@ export class KubeStatus { } } -export type IKubeMetaField = keyof IKubeObjectMetadata; +export type KubeMetaField = keyof KubeObjectMetadata; -export class KubeObject implements ItemObject { +export class KubeObject implements ItemObject { static readonly kind: string; static readonly namespaced: boolean; @@ -277,14 +277,14 @@ export class KubeObject(data: Partial): Promise { + async update(data: Partial): Promise { for (const field of KubeObject.nonEditableFields) { if (!_.isEqual(_.get(this, field), _.get(data, field))) { throw new Error(`Failed to update Kube Object: ${field} has been modified`); } } - return resourceApplierApi.update({ + return resourceApplierApi.update({ ...this.toPlainObject(), ...data, }); diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 1a0f7e0b17..4d316b5caa 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -31,8 +31,9 @@ import { autoBind, Disposer, noop } from "../utils"; import type { KubeApi } from "./kube-api"; import type { KubeJsonApiData } from "./kube-json-api"; import { isDebugging, isProduction } from "../../common/vars"; +import type { KubeObject } from "./kube-object"; -export interface IKubeWatchEvent { +export interface IKubeWatchEvent { type: "ADDED" | "MODIFIED" | "DELETED" | "ERROR"; object?: T; } @@ -58,11 +59,11 @@ export class KubeWatchApi { autoBind(this); } - isAllowedApi(api: KubeApi): boolean { + isAllowedApi(api: KubeApi): boolean { return Boolean(this.context?.cluster.isAllowedResource(api.kind)); } - preloadStores(stores: KubeObjectStore[], opts: { namespaces?: string[], loadOnce?: boolean } = {}) { + preloadStores(stores: KubeObjectStore[], opts: { namespaces?: string[], loadOnce?: boolean } = {}) { const limitRequests = plimit(1); // load stores one by one to allow quick skipping when fast clicking btw pages const preloading: Promise[] = []; @@ -80,7 +81,7 @@ export class KubeWatchApi { }; } - subscribeStores(stores: KubeObjectStore[], opts: IKubeWatchSubscribeStoreOptions = {}): Disposer { + subscribeStores(stores: KubeObjectStore[], opts: IKubeWatchSubscribeStoreOptions = {}): Disposer { const { preload = true, waitUntilLoaded = true, loadOnce = false, } = opts; const subscribingNamespaces = opts.namespaces ?? this.context?.allNamespaces ?? []; const unsubscribeList: Function[] = []; diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index 455c95e7e8..1fc1dbf7b0 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -83,14 +83,14 @@ export class HelmCharts extends Component { store={helmChartStore} isSelectable={false} sortingCallbacks={{ - [columnId.name]: (chart: HelmChart) => chart.getName(), - [columnId.repo]: (chart: HelmChart) => chart.getRepository(), + [columnId.name]: chart => chart.getName(), + [columnId.repo]: chart => chart.getRepository(), }} searchFilters={[ - (chart: HelmChart) => chart.getName(), - (chart: HelmChart) => chart.getVersion(), - (chart: HelmChart) => chart.getAppVersion(), - (chart: HelmChart) => chart.getKeywords(), + chart => chart.getName(), + chart => chart.getVersion(), + chart => chart.getAppVersion(), + chart => chart.getKeywords(), ]} customizeHeader={({ searchProps }) => ({ searchProps: { @@ -106,7 +106,7 @@ export class HelmCharts extends Component { { title: "App Version", className: "app-version", id: columnId.appVersion }, { title: "Repository", className: "repository", sortBy: columnId.repo, id: columnId.repo }, ]} - renderTableContents={(chart: HelmChart) => [ + renderTableContents={chart => [
{ store={releaseStore} dependentStores={[secretsStore]} sortingCallbacks={{ - [columnId.name]: (release: HelmRelease) => release.getName(), - [columnId.namespace]: (release: HelmRelease) => release.getNs(), - [columnId.revision]: (release: HelmRelease) => release.getRevision(), - [columnId.chart]: (release: HelmRelease) => release.getChart(), - [columnId.status]: (release: HelmRelease) => release.getStatus(), - [columnId.updated]: (release: HelmRelease) => release.getUpdated(false, false), + [columnId.name]: release => release.getName(), + [columnId.namespace]: release => release.getNs(), + [columnId.revision]: release => release.getRevision(), + [columnId.chart]: release => release.getChart(), + [columnId.status]: release => release.getStatus(), + [columnId.updated]: release => release.getUpdated(false, false), }} searchFilters={[ - (release: HelmRelease) => release.getName(), - (release: HelmRelease) => release.getNs(), - (release: HelmRelease) => release.getChart(), - (release: HelmRelease) => release.getStatus(), - (release: HelmRelease) => release.getVersion(), + release => release.getName(), + release => release.getNs(), + release => release.getChart(), + release => release.getStatus(), + release => release.getVersion(), ]} customizeHeader={({ filters, searchProps, ...headerPlaceholders }) => ({ filters: ( @@ -149,7 +149,7 @@ export class HelmReleases extends Component { { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, { title: "Updated", className: "updated", sortBy: columnId.updated, id: columnId.updated }, ]} - renderTableContents={(release: HelmRelease) => [ + renderTableContents={release => [ release.getName(), release.getNs(), release.getChart(), @@ -159,13 +159,13 @@ export class HelmReleases extends Component { { title: release.getStatus(), className: kebabCase(release.getStatus()) }, release.getUpdated(), ]} - renderItemMenu={(release: HelmRelease) => ( + renderItemMenu={release => ( )} - customizeRemoveDialog={(selectedItems: HelmRelease[]) => ({ + customizeRemoveDialog={selectedItems => ({ message: this.renderRemoveDialogMessage(selectedItems) })} detailsItem={this.selectedRelease} diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index e70a8d5f47..4256170649 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -44,7 +44,6 @@ import { CatalogMenu } from "./catalog-menu"; import { HotbarIcon } from "../hotbar/hotbar-icon"; import { RenderDelay } from "../render-delay/render-delay"; import { CatalogTopbar } from "../cluster-manager/catalog-topbar"; -import type { TableSortCallback } from "../table"; export const previousActiveTab = createAppStorage("catalog-previous-active-tab", ""); @@ -168,7 +167,7 @@ export class Catalog extends React.Component { )) } - this.addToHotbar(item) }> + this.addToHotbar(item)}> Pin to Hotbar @@ -194,16 +193,6 @@ export class Catalog extends React.Component { renderList() { const { activeCategory } = this.catalogEntityStore; const tableId = activeCategory ? `catalog-items-${activeCategory.metadata.name.replace(" ", "")}` : "catalog-items"; - let sortingCallbacks: { [sortBy: string]: TableSortCallback } = { - [sortBy.name]: (item: CatalogEntityItem) => item.name, - [sortBy.source]: (item: CatalogEntityItem) => item.source, - [sortBy.status]: (item: CatalogEntityItem) => item.phase, - }; - - sortingCallbacks = activeCategory ? sortingCallbacks : { - ...sortingCallbacks, - [sortBy.kind]: (item: CatalogEntityItem) => item.kind, - }; if (this.activeTab === undefined) { return null; @@ -217,9 +206,14 @@ export class Catalog extends React.Component { isConfigurable={true} className="CatalogItemList" store={this.catalogEntityStore} - sortingCallbacks={sortingCallbacks} + sortingCallbacks={{ + [sortBy.name]: item => item.name, + [sortBy.source]: item => item.source, + [sortBy.status]: item => item.phase, + [sortBy.kind]: item => item.kind, + }} searchFilters={[ - (entity: CatalogEntityItem) => entity.searchFields, + entity => entity.searchFields, ]} renderTableHeader={[ { title: "", className: css.iconCell, id: "icon" }, @@ -229,10 +223,10 @@ export class Catalog extends React.Component { { title: "Labels", className: css.labelsCell, id: "labels" }, { title: "Status", className: css.statusCell, sortBy: sortBy.status, id: "status" }, ].filter(Boolean)} - customizeTableRowProps={(item: CatalogEntityItem) => ({ + customizeTableRowProps={item => ({ disabled: !item.enabled, })} - renderTableContents={(item: CatalogEntityItem) => [ + renderTableContents={item => [ this.renderIcon(item), item.name, !activeCategory && item.kind, diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index 539bbb18d7..35bf3d6375 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -64,15 +64,15 @@ export class HorizontalPodAutoscalers extends React.Component { tableId="configuration_hpa" className="HorizontalPodAutoscalers" store={hpaStore} sortingCallbacks={{ - [columnId.name]: (item: HorizontalPodAutoscaler) => item.getName(), - [columnId.namespace]: (item: HorizontalPodAutoscaler) => item.getNs(), - [columnId.minPods]: (item: HorizontalPodAutoscaler) => item.getMinPods(), - [columnId.maxPods]: (item: HorizontalPodAutoscaler) => item.getMaxPods(), - [columnId.replicas]: (item: HorizontalPodAutoscaler) => item.getReplicas(), - [columnId.age]: (item: HorizontalPodAutoscaler) => item.getTimeDiffFromNow(), + [columnId.name]: item => item.getName(), + [columnId.namespace]: item => item.getNs(), + [columnId.minPods]: item => item.getMinPods(), + [columnId.maxPods]: item => item.getMaxPods(), + [columnId.replicas]: item => item.getReplicas(), + [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - (item: HorizontalPodAutoscaler) => item.getSearchFields() + item => item.getSearchFields() ]} renderHeaderTitle="Horizontal Pod Autoscalers" renderTableHeader={[ @@ -86,7 +86,7 @@ export class HorizontalPodAutoscalers extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Status", className: "status", id: columnId.status }, ]} - renderTableContents={(hpa: HorizontalPodAutoscaler) => [ + renderTableContents={hpa => [ hpa.getName(), , hpa.getNs(), diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx index 664654814c..e0bec106aa 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx @@ -27,7 +27,6 @@ import { KubeObjectListLayout } from "../kube-object/kube-object-list-layout"; import { limitRangeStore } from "./limit-ranges.store"; import React from "react"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; -import type { LimitRange } from "../../api/endpoints/limit-range.api"; import type { LimitRangeRouteParams } from "../../../common/routes"; enum columnId { @@ -49,22 +48,22 @@ export class LimitRanges extends React.Component { className="LimitRanges" store={limitRangeStore} sortingCallbacks={{ - [columnId.name]: (item: LimitRange) => item.getName(), - [columnId.namespace]: (item: LimitRange) => item.getNs(), - [columnId.age]: (item: LimitRange) => item.getTimeDiffFromNow(), + [columnId.name]: item => item.getName(), + [columnId.namespace]: item => item.getNs(), + [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - (item: LimitRange) => item.getName(), - (item: LimitRange) => item.getNs(), + item => item.getName(), + item => item.getNs(), ]} - renderHeaderTitle={"Limit Ranges"} + renderHeaderTitle="Limit Ranges" renderTableHeader={[ { title: "Name", className: "name", sortBy: columnId.name, id: columnId.name }, { className: "warning", showWithColumn: columnId.name }, { title: "Namespace", className: "namespace", sortBy: columnId.namespace, id: columnId.namespace }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(limitRange: LimitRange) => [ + renderTableContents={limitRange => [ limitRange.getName(), , limitRange.getNs(), diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index fb757a69bf..b9fecc9fc9 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -25,7 +25,6 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { configMapsStore } from "./config-maps.store"; -import type { ConfigMap } from "../../api/endpoints/configmap.api"; import { KubeObjectListLayout } from "../kube-object"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { ConfigMapsRouteParams } from "../../../common/routes"; @@ -49,14 +48,14 @@ export class ConfigMaps extends React.Component { tableId="configuration_configmaps" className="ConfigMaps" store={configMapsStore} sortingCallbacks={{ - [columnId.name]: (item: ConfigMap) => item.getName(), - [columnId.namespace]: (item: ConfigMap) => item.getNs(), - [columnId.keys]: (item: ConfigMap) => item.getKeys(), - [columnId.age]: (item: ConfigMap) => item.getTimeDiffFromNow(), + [columnId.name]: item => item.getName(), + [columnId.namespace]: item => item.getNs(), + [columnId.keys]: item => item.getKeys(), + [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - (item: ConfigMap) => item.getSearchFields(), - (item: ConfigMap) => item.getKeys() + item => item.getSearchFields(), + item => item.getKeys() ]} renderHeaderTitle="Config Maps" renderTableHeader={[ @@ -66,7 +65,7 @@ export class ConfigMaps extends React.Component { { title: "Keys", className: "keys", sortBy: columnId.keys, id: columnId.keys }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(configMap: ConfigMap) => [ + renderTableContents={configMap => [ configMap.getName(), , configMap.getNs(), diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx index abc87a6a4d..f662c96ab3 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx @@ -51,16 +51,16 @@ export class PodDisruptionBudgets extends React.Component { className="PodDisruptionBudgets" store={podDisruptionBudgetsStore} sortingCallbacks={{ - [columnId.name]: (pdb: PodDisruptionBudget) => pdb.getName(), - [columnId.namespace]: (pdb: PodDisruptionBudget) => pdb.getNs(), - [columnId.minAvailable]: (pdb: PodDisruptionBudget) => pdb.getMinAvailable(), - [columnId.maxUnavailable]: (pdb: PodDisruptionBudget) => pdb.getMaxUnavailable(), - [columnId.currentHealthy]: (pdb: PodDisruptionBudget) => pdb.getCurrentHealthy(), - [columnId.desiredHealthy]: (pdb: PodDisruptionBudget) => pdb.getDesiredHealthy(), - [columnId.age]: (pdb: PodDisruptionBudget) => pdb.getAge(), + [columnId.name]: pdb => pdb.getName(), + [columnId.namespace]: pdb => pdb.getNs(), + [columnId.minAvailable]: pdb => pdb.getMinAvailable(), + [columnId.maxUnavailable]: pdb => pdb.getMaxUnavailable(), + [columnId.currentHealthy]: pdb => pdb.getCurrentHealthy(), + [columnId.desiredHealthy]: pdb => pdb.getDesiredHealthy(), + [columnId.age]: pdb => pdb.getAge(), }} searchFilters={[ - (pdb: PodDisruptionBudget) => pdb.getSearchFields(), + pdb => pdb.getSearchFields(), ]} renderHeaderTitle="Pod Disruption Budgets" renderTableHeader={[ @@ -73,7 +73,7 @@ export class PodDisruptionBudgets extends React.Component { { title: "Desired Healthy", className: "desired-healthy", sortBy: columnId.desiredHealthy, id: columnId.desiredHealthy }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(pdb: PodDisruptionBudget) => { + renderTableContents={pdb => { return [ pdb.getName(), , diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx index d1ce05c098..e1f54f2499 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -25,7 +25,6 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -import type { ResourceQuota } from "../../api/endpoints/resource-quota.api"; import { AddQuotaDialog } from "./add-quota-dialog"; import { resourceQuotaStore } from "./resource-quotas.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; @@ -50,13 +49,13 @@ export class ResourceQuotas extends React.Component { tableId="configuration_quotas" className="ResourceQuotas" store={resourceQuotaStore} sortingCallbacks={{ - [columnId.name]: (item: ResourceQuota) => item.getName(), - [columnId.namespace]: (item: ResourceQuota) => item.getNs(), - [columnId.age]: (item: ResourceQuota) => item.getTimeDiffFromNow(), + [columnId.name]: item => item.getName(), + [columnId.namespace]: item => item.getNs(), + [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - (item: ResourceQuota) => item.getSearchFields(), - (item: ResourceQuota) => item.getName(), + item => item.getSearchFields(), + item => item.getName(), ]} renderHeaderTitle="Resource Quotas" renderTableHeader={[ @@ -65,7 +64,7 @@ export class ResourceQuotas extends React.Component { { title: "Namespace", className: "namespace", sortBy: columnId.namespace, id: columnId.namespace }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(resourceQuota: ResourceQuota) => [ + renderTableContents={resourceQuota => [ resourceQuota.getName(), , resourceQuota.getNs(), diff --git a/src/renderer/components/+config-secrets/add-secret-dialog.tsx b/src/renderer/components/+config-secrets/add-secret-dialog.tsx index 23adfaf804..5c417023e2 100644 --- a/src/renderer/components/+config-secrets/add-secret-dialog.tsx +++ b/src/renderer/components/+config-secrets/add-secret-dialog.tsx @@ -33,7 +33,7 @@ import { SubTitle } from "../layout/sub-title"; import { NamespaceSelect } from "../+namespaces/namespace-select"; import { Select, SelectOption } from "../select"; import { Icon } from "../icon"; -import type { IKubeObjectMetadata } from "../../api/kube-object"; +import type { KubeObjectMetadata } from "../../api/kube-object"; import { base64 } from "../../utils"; import { Notifications } from "../notifications"; import upperFirst from "lodash/upperFirst"; @@ -127,7 +127,7 @@ export class AddSecretDialog extends React.Component { namespace, annotations: this.getDataFromFields(annotations), labels: this.getDataFromFields(labels), - } as IKubeObjectMetadata + } as KubeObjectMetadata }; try { diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index 3bfeada163..f00c20d67e 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -24,7 +24,6 @@ import "./secrets.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import type { Secret } from "../../api/endpoints"; import { AddSecretDialog } from "./add-secret-dialog"; import { KubeObjectListLayout } from "../kube-object"; import { Badge } from "../badge"; @@ -54,16 +53,16 @@ export class Secrets extends React.Component { tableId="configuration_secrets" className="Secrets" store={secretsStore} sortingCallbacks={{ - [columnId.name]: (item: Secret) => item.getName(), - [columnId.namespace]: (item: Secret) => item.getNs(), - [columnId.labels]: (item: Secret) => item.getLabels(), - [columnId.keys]: (item: Secret) => item.getKeys(), - [columnId.type]: (item: Secret) => item.type, - [columnId.age]: (item: Secret) => item.getTimeDiffFromNow(), + [columnId.name]: item => item.getName(), + [columnId.namespace]: item => item.getNs(), + [columnId.labels]: item => item.getLabels(), + [columnId.keys]: item => item.getKeys(), + [columnId.type]: item => item.type, + [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - (item: Secret) => item.getSearchFields(), - (item: Secret) => item.getKeys(), + item => item.getSearchFields(), + item => item.getKeys(), ]} renderHeaderTitle="Secrets" renderTableHeader={[ @@ -75,7 +74,7 @@ export class Secrets extends React.Component { { title: "Type", className: "type", sortBy: columnId.type, id: columnId.type }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(secret: Secret) => [ + renderTableContents={secret => [ secret.getName(), , secret.getNs(), diff --git a/src/renderer/components/+custom-resources/crd-list.tsx b/src/renderer/components/+custom-resources/crd-list.tsx index e8bfee160d..70ae2c96fb 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -32,6 +32,7 @@ import type { CustomResourceDefinition } from "../../api/endpoints/crd.api"; import { Select, SelectOption } from "../select"; import { createPageParam } from "../../navigation"; import { Icon } from "../icon"; +import type { TableSortCallbacks } from "../table"; export const crdGroupsUrlParam = createPageParam({ name: "groups", @@ -78,11 +79,11 @@ export class CrdList extends React.Component { render() { const { items, selectedGroups } = this; - const sortingCallbacks = { - [columnId.kind]: (crd: CustomResourceDefinition) => crd.getResourceKind(), - [columnId.group]: (crd: CustomResourceDefinition) => crd.getGroup(), - [columnId.version]: (crd: CustomResourceDefinition) => crd.getVersion(), - [columnId.scope]: (crd: CustomResourceDefinition) => crd.getScope(), + const sortingCallbacks: TableSortCallbacks = { + [columnId.kind]: crd => crd.getResourceKind(), + [columnId.group]: crd => crd.getGroup(), + [columnId.version]: crd => crd.getVersion(), + [columnId.scope]: crd => crd.getScope(), }; return ( @@ -137,7 +138,7 @@ export class CrdList extends React.Component { { title: "Scope", className: "scope", sortBy: columnId.scope, id: columnId.scope }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(crd: CustomResourceDefinition) => [ + renderTableContents={crd => [ {crd.getResourceKind()} , diff --git a/src/renderer/components/+custom-resources/crd-resource.store.ts b/src/renderer/components/+custom-resources/crd-resource.store.ts index 8717884785..335a015aa7 100644 --- a/src/renderer/components/+custom-resources/crd-resource.store.ts +++ b/src/renderer/components/+custom-resources/crd-resource.store.ts @@ -23,10 +23,10 @@ import type { KubeApi } from "../../api/kube-api"; import { KubeObjectStore } from "../../kube-object.store"; import type { KubeObject } from "../../api/kube-object"; -export class CRDResourceStore extends KubeObjectStore { - api: KubeApi; +export class CRDResourceStore extends KubeObjectStore { + api: KubeApi; - constructor(api: KubeApi) { + constructor(api: KubeApi) { super(); this.api = api; } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index 0203bef3da..6042b82027 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -29,7 +29,7 @@ import { KubeObjectListLayout } from "../kube-object"; import type { KubeObject } from "../../api/kube-object"; import { autorun, computed, makeObservable } from "mobx"; import { crdStore } from "./crd.store"; -import type { TableSortCallback } from "../table"; +import type { TableSortCallbacks } from "../table"; import { apiManager } from "../../api/api-manager"; import { parseJsonPath } from "../../utils/jsonPath"; import type { CRDRouteParams } from "../../../common/routes"; @@ -80,14 +80,14 @@ export class CrdResources extends React.Component { if (!crd) return null; const isNamespaced = crd.isNamespaced(); const extraColumns = crd.getPrinterColumns(false); // Cols with priority bigger than 0 are shown in details - const sortingCallbacks: { [sortBy: string]: TableSortCallback } = { - [columnId.name]: (item: KubeObject) => item.getName(), - [columnId.namespace]: (item: KubeObject) => item.getNs(), - [columnId.age]: (item: KubeObject) => item.getTimeDiffFromNow(), + const sortingCallbacks: TableSortCallbacks = { + [columnId.name]: item => item.getName(), + [columnId.namespace]: item => item.getNs(), + [columnId.age]: item => item.getTimeDiffFromNow(), }; extraColumns.forEach(column => { - sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, parseJsonPath(column.jsonPath.slice(1))); + sortingCallbacks[column.name] = item => jsonPath.value(item, parseJsonPath(column.jsonPath.slice(1))); }); return ( @@ -98,7 +98,7 @@ export class CrdResources extends React.Component { store={store} sortingCallbacks={sortingCallbacks} searchFilters={[ - (item: KubeObject) => item.getSearchFields(), + item => item.getSearchFields(), ]} renderHeaderTitle={crd.getResourceTitle()} customizeHeader={({ searchProps, ...headerPlaceholders }) => ({ @@ -123,7 +123,7 @@ export class CrdResources extends React.Component { }), { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(crdInstance: KubeObject) => [ + renderTableContents={crdInstance => [ crdInstance.getName(), isNamespaced && crdInstance.getNs(), ...extraColumns.map((column) => { diff --git a/src/renderer/components/+custom-resources/crd.store.ts b/src/renderer/components/+custom-resources/crd.store.ts index 613438bca7..25415e5ab3 100644 --- a/src/renderer/components/+custom-resources/crd.store.ts +++ b/src/renderer/components/+custom-resources/crd.store.ts @@ -26,13 +26,18 @@ import { crdApi, CustomResourceDefinition } from "../../api/endpoints/crd.api"; import { apiManager } from "../../api/api-manager"; import { KubeApi } from "../../api/kube-api"; import { CRDResourceStore } from "./crd-resource.store"; -import type { KubeObject } from "../../api/kube-object"; +import { KubeObject } from "../../api/kube-object"; function initStore(crd: CustomResourceDefinition) { const apiBase = crd.getResourceApiBase(); const kind = crd.getResourceKind(); const isNamespaced = crd.isNamespaced(); - const api = apiManager.getApi(apiBase) || new KubeApi({ apiBase, kind, isNamespaced }); + const api = apiManager.getApi(apiBase) ?? new KubeApi({ + objectConstructor: KubeObject, + apiBase, + kind, + isNamespaced, + }); if (!apiManager.getStore(api)) { apiManager.registerStore(new CRDResourceStore(api)); diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index f0d95bd41e..23aa985ab8 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -29,7 +29,7 @@ import { TabLayout } from "../layout/tab-layout"; import { EventStore, eventStore } from "./event.store"; import { getDetailsUrl, KubeObjectListLayout, KubeObjectListLayoutProps } from "../kube-object"; import type { KubeEvent } from "../../api/endpoints/events.api"; -import type { TableSortCallbacks, TableSortParams, TableProps } from "../table"; +import type { TableSortCallbacks, TableSortParams } from "../table"; import type { HeaderCustomizer } from "../item-object-list"; import { Tooltip } from "../tooltip"; import { Link } from "react-router-dom"; @@ -49,7 +49,7 @@ enum columnId { lastSeen = "last-seen", } -interface Props extends Partial { +interface Props extends Partial> { className?: IClassName; compact?: boolean; compactLimit?: number; @@ -69,19 +69,13 @@ export class Events extends React.Component { orderBy: "asc", }; - private sortingCallbacks: TableSortCallbacks = { - [columnId.namespace]: (event: KubeEvent) => event.getNs(), - [columnId.type]: (event: KubeEvent) => event.type, - [columnId.object]: (event: KubeEvent) => event.involvedObject.name, - [columnId.count]: (event: KubeEvent) => event.count, - [columnId.age]: (event: KubeEvent) => event.getTimeDiffFromNow(), - [columnId.lastSeen]: (event: KubeEvent) => this.now - new Date(event.lastTimestamp).getTime(), - }; - - private tableConfiguration: TableProps = { - sortSyncWithUrl: false, - sortByDefault: this.sorting, - onSort: params => this.sorting = params, + private sortingCallbacks: TableSortCallbacks = { + [columnId.namespace]: event => event.getNs(), + [columnId.type]: event => event.type, + [columnId.object]: event => event.involvedObject.name, + [columnId.count]: event => event.count, + [columnId.age]: event => event.getTimeDiffFromNow(), + [columnId.lastSeen]: event => this.now - new Date(event.lastTimestamp).getTime(), }; constructor(props: Props) { @@ -160,13 +154,17 @@ export class Events extends React.Component { isSelectable={false} items={visibleItems} virtual={!compact} - tableProps={this.tableConfiguration} + tableProps={{ + sortSyncWithUrl: false, + sortByDefault: this.sorting, + onSort: params => this.sorting = params, + }} sortingCallbacks={this.sortingCallbacks} searchFilters={[ - (event: KubeEvent) => event.getSearchFields(), - (event: KubeEvent) => event.message, - (event: KubeEvent) => event.getSource(), - (event: KubeEvent) => event.involvedObject.name, + event => event.getSearchFields(), + event => event.message, + event => event.getSource(), + event => event.involvedObject.name, ]} renderTableHeader={[ { title: "Type", className: "type", sortBy: columnId.type, id: columnId.type }, @@ -178,7 +176,7 @@ export class Events extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Last Seen", className: "last-seen", sortBy: columnId.lastSeen, id: columnId.lastSeen }, ]} - renderTableContents={(event: KubeEvent) => { + renderTableContents={event => { const { involvedObject, type, message } = event; const tooltipId = `message-${event.getId()}`; const isWarning = event.isWarning(); diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index e8db0948ca..cc4a8b98ce 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -109,7 +109,7 @@ export class NamespaceStore extends KubeObjectStore { return super.subscribe(); } - protected async loadItems(params: KubeObjectStoreLoadingParams) { + protected async loadItems(params: KubeObjectStoreLoadingParams): Promise { const { allowedNamespaces } = this; let namespaces = await super.loadItems(params).catch(() => []); diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index c80c839071..cc29fa05ea 100644 --- a/src/renderer/components/+namespaces/namespaces.tsx +++ b/src/renderer/components/+namespaces/namespaces.tsx @@ -22,7 +22,7 @@ import "./namespaces.scss"; import React from "react"; -import { Namespace, NamespaceStatus } from "../../api/endpoints"; +import { NamespaceStatus } from "../../api/endpoints"; import { AddNamespaceDialog } from "./add-namespace-dialog"; import { TabLayout } from "../layout/tab-layout"; import { Badge } from "../badge"; @@ -51,14 +51,14 @@ export class Namespaces extends React.Component { tableId="namespaces" className="Namespaces" store={namespaceStore} sortingCallbacks={{ - [columnId.name]: (ns: Namespace) => ns.getName(), - [columnId.labels]: (ns: Namespace) => ns.getLabels(), - [columnId.age]: (ns: Namespace) => ns.getTimeDiffFromNow(), - [columnId.status]: (ns: Namespace) => ns.getStatus(), + [columnId.name]: ns => ns.getName(), + [columnId.labels]: ns => ns.getLabels(), + [columnId.age]: ns => ns.getTimeDiffFromNow(), + [columnId.status]: ns => ns.getStatus(), }} searchFilters={[ - (item: Namespace) => item.getSearchFields(), - (item: Namespace) => item.getStatus() + item => item.getSearchFields(), + item => item.getStatus() ]} renderHeaderTitle="Namespaces" renderTableHeader={[ @@ -68,7 +68,7 @@ export class Namespaces extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} - renderTableContents={(item: Namespace) => [ + renderTableContents={item => [ item.getName(), , item.getLabels().map(label => ), @@ -79,7 +79,7 @@ export class Namespaces extends React.Component { addTooltip: "Add Namespace", onAdd: () => AddNamespaceDialog.open(), }} - customizeTableRowProps={(item: Namespace) => ({ + customizeTableRowProps={item => ({ disabled: item.getStatus() === NamespaceStatus.TERMINATING, })} /> diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index 3ae66884fa..940ab89783 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -24,7 +24,6 @@ import "./endpoints.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; -import type { Endpoint } from "../../api/endpoints/endpoint.api"; import { endpointStore } from "./endpoints.store"; import { KubeObjectListLayout } from "../kube-object"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; @@ -49,12 +48,12 @@ export class Endpoints extends React.Component { tableId="network_endpoints" className="Endpoints" store={endpointStore} sortingCallbacks={{ - [columnId.name]: (endpoint: Endpoint) => endpoint.getName(), - [columnId.namespace]: (endpoint: Endpoint) => endpoint.getNs(), - [columnId.age]: (endpoint: Endpoint) => endpoint.getTimeDiffFromNow(), + [columnId.name]: endpoint => endpoint.getName(), + [columnId.namespace]: endpoint => endpoint.getNs(), + [columnId.age]: endpoint => endpoint.getTimeDiffFromNow(), }} searchFilters={[ - (endpoint: Endpoint) => endpoint.getSearchFields() + endpoint => endpoint.getSearchFields() ]} renderHeaderTitle="Endpoints" renderTableHeader={[ @@ -64,7 +63,7 @@ export class Endpoints extends React.Component { { title: "Endpoints", className: "endpoints", id: columnId.endpoints }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(endpoint: Endpoint) => [ + renderTableContents={endpoint => [ endpoint.getName(), , endpoint.getNs(), @@ -72,7 +71,7 @@ export class Endpoints extends React.Component { endpoint.getAge(), ]} tableProps={{ - customRowHeights: (item: Endpoint, lineHeight, paddings) => { + customRowHeights: (item, lineHeight, paddings) => { const lines = item.getEndpointSubsets().length || 1; return lines * lineHeight + paddings; diff --git a/src/renderer/components/+network-ingresses/ingresses.tsx b/src/renderer/components/+network-ingresses/ingresses.tsx index 2a15bf5cb8..153a4eb62f 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -24,7 +24,6 @@ import "./ingresses.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; -import type { Ingress } from "../../api/endpoints/ingress.api"; import { ingressStore } from "./ingress.store"; import { KubeObjectListLayout } from "../kube-object"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; @@ -50,13 +49,13 @@ export class Ingresses extends React.Component { tableId="network_ingresses" className="Ingresses" store={ingressStore} sortingCallbacks={{ - [columnId.name]: (ingress: Ingress) => ingress.getName(), - [columnId.namespace]: (ingress: Ingress) => ingress.getNs(), - [columnId.age]: (ingress: Ingress) => ingress.getTimeDiffFromNow(), + [columnId.name]: ingress => ingress.getName(), + [columnId.namespace]: ingress => ingress.getNs(), + [columnId.age]: ingress => ingress.getTimeDiffFromNow(), }} searchFilters={[ - (ingress: Ingress) => ingress.getSearchFields(), - (ingress: Ingress) => ingress.getPorts(), + ingress => ingress.getSearchFields(), + ingress => ingress.getPorts(), ]} renderHeaderTitle="Ingresses" renderTableHeader={[ @@ -67,7 +66,7 @@ export class Ingresses extends React.Component { { title: "Rules", className: "rules", id: columnId.rules }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(ingress: Ingress) => [ + renderTableContents={ingress => [ ingress.getName(), , ingress.getNs(), @@ -76,7 +75,7 @@ export class Ingresses extends React.Component { ingress.getAge(), ]} tableProps={{ - customRowHeights: (item: Ingress, lineHeight, paddings) => { + customRowHeights: (item, lineHeight, paddings) => { const lines = item.getRoutes().length || 1; return lines * lineHeight + paddings; diff --git a/src/renderer/components/+network-policies/network-policies.tsx b/src/renderer/components/+network-policies/network-policies.tsx index 6aa63eff23..65579eaa56 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -24,7 +24,6 @@ import "./network-policies.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; -import type { NetworkPolicy } from "../../api/endpoints/network-policy.api"; import { KubeObjectListLayout } from "../kube-object"; import { networkPolicyStore } from "./network-policy.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; @@ -49,12 +48,12 @@ export class NetworkPolicies extends React.Component { tableId="network_policies" className="NetworkPolicies" store={networkPolicyStore} sortingCallbacks={{ - [columnId.name]: (item: NetworkPolicy) => item.getName(), - [columnId.namespace]: (item: NetworkPolicy) => item.getNs(), - [columnId.age]: (item: NetworkPolicy) => item.getTimeDiffFromNow(), + [columnId.name]: item => item.getName(), + [columnId.namespace]: item => item.getNs(), + [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - (item: NetworkPolicy) => item.getSearchFields(), + item => item.getSearchFields(), ]} renderHeaderTitle="Network Policies" renderTableHeader={[ @@ -64,7 +63,7 @@ export class NetworkPolicies extends React.Component { { title: "Policy Types", className: "type", id: columnId.types }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(item: NetworkPolicy) => [ + renderTableContents={item => [ item.getName(), , item.getNs(), diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index 502955b630..745236be61 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -24,7 +24,6 @@ import "./services.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import type { Service } from "../../api/endpoints/service.api"; import { KubeObjectListLayout } from "../kube-object"; import { Badge } from "../badge"; import { serviceStore } from "./services.store"; @@ -55,19 +54,19 @@ export class Services extends React.Component { tableId="network_services" className="Services" store={serviceStore} sortingCallbacks={{ - [columnId.name]: (service: Service) => service.getName(), - [columnId.namespace]: (service: Service) => service.getNs(), - [columnId.selector]: (service: Service) => service.getSelector(), - [columnId.ports]: (service: Service) => (service.spec.ports || []).map(({ port }) => port)[0], - [columnId.clusterIp]: (service: Service) => service.getClusterIp(), - [columnId.type]: (service: Service) => service.getType(), - [columnId.age]: (service: Service) => service.getTimeDiffFromNow(), - [columnId.status]: (service: Service) => service.getStatus(), + [columnId.name]: service => service.getName(), + [columnId.namespace]: service => service.getNs(), + [columnId.selector]: service => service.getSelector(), + [columnId.ports]: service => (service.spec.ports || []).map(({ port }) => port)[0], + [columnId.clusterIp]: service => service.getClusterIp(), + [columnId.type]: service => service.getType(), + [columnId.age]: service => service.getTimeDiffFromNow(), + [columnId.status]: service => service.getStatus(), }} searchFilters={[ - (service: Service) => service.getSearchFields(), - (service: Service) => service.getSelector().join(" "), - (service: Service) => service.getPorts().join(" "), + service => service.getSearchFields(), + service => service.getSelector().join(" "), + service => service.getPorts().join(" "), ]} renderHeaderTitle="Services" renderTableHeader={[ @@ -82,7 +81,7 @@ export class Services extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} - renderTableContents={(service: Service) => [ + renderTableContents={service => [ service.getName(), , service.getNs(), diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 4b5672b816..1225ea8c15 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -198,21 +198,21 @@ export class Nodes extends React.Component { dependentStores={[podsStore]} isSelectable={false} sortingCallbacks={{ - [columnId.name]: (node: Node) => node.getName(), - [columnId.cpu]: (node: Node) => this.getLastMetricValues(node, ["cpuUsage"]), - [columnId.memory]: (node: Node) => this.getLastMetricValues(node, ["memoryUsage"]), - [columnId.disk]: (node: Node) => this.getLastMetricValues(node, ["fsUsage"]), - [columnId.conditions]: (node: Node) => node.getNodeConditionText(), - [columnId.taints]: (node: Node) => node.getTaints().length, - [columnId.roles]: (node: Node) => node.getRoleLabels(), - [columnId.age]: (node: Node) => node.getTimeDiffFromNow(), - [columnId.version]: (node: Node) => node.getKubeletVersion(), + [columnId.name]: node => node.getName(), + [columnId.cpu]: node => this.getLastMetricValues(node, ["cpuUsage"]), + [columnId.memory]: node => this.getLastMetricValues(node, ["memoryUsage"]), + [columnId.disk]: node => this.getLastMetricValues(node, ["fsUsage"]), + [columnId.conditions]: node => node.getNodeConditionText(), + [columnId.taints]: node => node.getTaints().length, + [columnId.roles]: node => node.getRoleLabels(), + [columnId.age]: node => node.getTimeDiffFromNow(), + [columnId.version]: node => node.getKubeletVersion(), }} searchFilters={[ - (node: Node) => node.getSearchFields(), - (node: Node) => node.getRoleLabels(), - (node: Node) => node.getKubeletVersion(), - (node: Node) => node.getNodeConditionText(), + node => node.getSearchFields(), + node => node.getRoleLabels(), + node => node.getKubeletVersion(), + node => node.getNodeConditionText(), ]} renderHeaderTitle="Nodes" renderTableHeader={[ @@ -227,7 +227,7 @@ export class Nodes extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Conditions", className: "conditions", sortBy: columnId.conditions, id: columnId.conditions }, ]} - renderTableContents={(node: Node) => { + renderTableContents={node => { const tooltipId = `node-taints-${node.getId()}`; return [ diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx index a74a5e8623..c578bf8e34 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx @@ -25,7 +25,6 @@ import React from "react"; import { observer } from "mobx-react"; import { KubeObjectListLayout } from "../kube-object"; import { podSecurityPoliciesStore } from "./pod-security-policies.store"; -import type { PodSecurityPolicy } from "../../api/endpoints"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum columnId { @@ -45,15 +44,15 @@ export class PodSecurityPolicies extends React.Component { className="PodSecurityPolicies" store={podSecurityPoliciesStore} sortingCallbacks={{ - [columnId.name]: (item: PodSecurityPolicy) => item.getName(), - [columnId.volumes]: (item: PodSecurityPolicy) => item.getVolumes(), - [columnId.privileged]: (item: PodSecurityPolicy) => +item.isPrivileged(), - [columnId.age]: (item: PodSecurityPolicy) => item.getTimeDiffFromNow(), + [columnId.name]: item => item.getName(), + [columnId.volumes]: item => item.getVolumes(), + [columnId.privileged]: item => +item.isPrivileged(), + [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - (item: PodSecurityPolicy) => item.getSearchFields(), - (item: PodSecurityPolicy) => item.getVolumes(), - (item: PodSecurityPolicy) => Object.values(item.getRules()), + item => item.getSearchFields(), + item => item.getVolumes(), + item => Object.values(item.getRules()), ]} renderHeaderTitle="Pod Security Policies" renderTableHeader={[ @@ -63,7 +62,7 @@ export class PodSecurityPolicies extends React.Component { { title: "Volumes", className: "volumes", sortBy: columnId.volumes, id: columnId.volumes }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(item: PodSecurityPolicy) => { + renderTableContents={item => { return [ item.getName(), , diff --git a/src/renderer/components/+storage-classes/storage-classes.tsx b/src/renderer/components/+storage-classes/storage-classes.tsx index 9ccfca9448..d81d32041e 100644 --- a/src/renderer/components/+storage-classes/storage-classes.tsx +++ b/src/renderer/components/+storage-classes/storage-classes.tsx @@ -24,7 +24,6 @@ import "./storage-classes.scss"; import React from "react"; import type { RouteComponentProps } from "react-router-dom"; import { observer } from "mobx-react"; -import type { StorageClass } from "../../api/endpoints/storage-class.api"; import { KubeObjectListLayout } from "../kube-object"; import { storageClassStore } from "./storage-class.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; @@ -51,14 +50,14 @@ export class StorageClasses extends React.Component { className="StorageClasses" store={storageClassStore} sortingCallbacks={{ - [columnId.name]: (item: StorageClass) => item.getName(), - [columnId.age]: (item: StorageClass) => item.getTimeDiffFromNow(), - [columnId.provisioner]: (item: StorageClass) => item.provisioner, - [columnId.reclaimPolicy]: (item: StorageClass) => item.reclaimPolicy, + [columnId.name]: item => item.getName(), + [columnId.age]: item => item.getTimeDiffFromNow(), + [columnId.provisioner]: item => item.provisioner, + [columnId.reclaimPolicy]: item => item.reclaimPolicy, }} searchFilters={[ - (item: StorageClass) => item.getSearchFields(), - (item: StorageClass) => item.provisioner, + item => item.getSearchFields(), + item => item.provisioner, ]} renderHeaderTitle="Storage Classes" renderTableHeader={[ @@ -69,7 +68,7 @@ export class StorageClasses extends React.Component { { title: "Default", className: "is-default", id: columnId.default }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(storageClass: StorageClass) => [ + renderTableContents={storageClass => [ storageClass.getName(), , storageClass.provisioner, diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.tsx b/src/renderer/components/+storage-volume-claims/volume-claims.tsx index c222405756..60230033f9 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -25,7 +25,6 @@ import React from "react"; import { observer } from "mobx-react"; import { Link, RouteComponentProps } from "react-router-dom"; import { volumeClaimStore } from "./volume-claim.store"; -import type { PersistentVolumeClaim } from "../../api/endpoints/persistent-volume-claims.api"; import { podsStore } from "../+workloads-pods/pods.store"; import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; import { unitsToBytes } from "../../utils/convertMemory"; @@ -58,17 +57,17 @@ export class PersistentVolumeClaims extends React.Component { store={volumeClaimStore} dependentStores={[podsStore]} sortingCallbacks={{ - [columnId.name]: (pvc: PersistentVolumeClaim) => pvc.getName(), - [columnId.namespace]: (pvc: PersistentVolumeClaim) => pvc.getNs(), - [columnId.pods]: (pvc: PersistentVolumeClaim) => pvc.getPods(podsStore.items).map(pod => pod.getName()), - [columnId.status]: (pvc: PersistentVolumeClaim) => pvc.getStatus(), - [columnId.size]: (pvc: PersistentVolumeClaim) => unitsToBytes(pvc.getStorage()), - [columnId.storageClass]: (pvc: PersistentVolumeClaim) => pvc.spec.storageClassName, - [columnId.age]: (pvc: PersistentVolumeClaim) => pvc.getTimeDiffFromNow(), + [columnId.name]: pvc => pvc.getName(), + [columnId.namespace]: pvc => pvc.getNs(), + [columnId.pods]: pvc => pvc.getPods(podsStore.items).map(pod => pod.getName()), + [columnId.status]: pvc => pvc.getStatus(), + [columnId.size]: pvc => unitsToBytes(pvc.getStorage()), + [columnId.storageClass]: pvc => pvc.spec.storageClassName, + [columnId.age]: pvc => pvc.getTimeDiffFromNow(), }} searchFilters={[ - (item: PersistentVolumeClaim) => item.getSearchFields(), - (item: PersistentVolumeClaim) => item.getPods(podsStore.items).map(pod => pod.getName()), + item => item.getSearchFields(), + item => item.getPods(podsStore.items).map(pod => pod.getName()), ]} renderHeaderTitle="Persistent Volume Claims" renderTableHeader={[ @@ -81,7 +80,7 @@ export class PersistentVolumeClaims extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} - renderTableContents={(pvc: PersistentVolumeClaim) => { + renderTableContents={pvc => { const pods = pvc.getPods(podsStore.items); const { storageClassName } = pvc.spec; const storageClassDetailsUrl = getDetailsUrl(storageClassApi.getUrl({ diff --git a/src/renderer/components/+storage-volumes/volumes.tsx b/src/renderer/components/+storage-volumes/volumes.tsx index 8b60fc9afc..ce1e313e9b 100644 --- a/src/renderer/components/+storage-volumes/volumes.tsx +++ b/src/renderer/components/+storage-volumes/volumes.tsx @@ -24,7 +24,6 @@ import "./volumes.scss"; import React from "react"; import { observer } from "mobx-react"; import { Link, RouteComponentProps } from "react-router-dom"; -import type { PersistentVolume } from "../../api/endpoints/persistent-volume.api"; import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; import { stopPropagation } from "../../utils"; import { volumesStore } from "./volumes.store"; @@ -54,15 +53,15 @@ export class PersistentVolumes extends React.Component { className="PersistentVolumes" store={volumesStore} sortingCallbacks={{ - [columnId.name]: (item: PersistentVolume) => item.getName(), - [columnId.storageClass]: (item: PersistentVolume) => item.getStorageClass(), - [columnId.capacity]: (item: PersistentVolume) => item.getCapacity(true), - [columnId.status]: (item: PersistentVolume) => item.getStatus(), - [columnId.age]: (item: PersistentVolume) => item.getTimeDiffFromNow(), + [columnId.name]: item => item.getName(), + [columnId.storageClass]: item => item.getStorageClass(), + [columnId.capacity]: item => item.getCapacity(true), + [columnId.status]: item => item.getStatus(), + [columnId.age]: item => item.getTimeDiffFromNow(), }} searchFilters={[ - (item: PersistentVolume) => item.getSearchFields(), - (item: PersistentVolume) => item.getClaimRefName(), + item => item.getSearchFields(), + item => item.getClaimRefName(), ]} renderHeaderTitle="Persistent Volumes" renderTableHeader={[ @@ -74,7 +73,7 @@ export class PersistentVolumes extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} - renderTableContents={(volume: PersistentVolume) => { + renderTableContents={volume => { const { claimRef, storageClassName } = volume.spec; const storageClassDetailsUrl = getDetailsUrl(storageClassApi.getUrl({ name: storageClassName diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/view.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/view.tsx index 2cf5b95037..cb1f542fd1 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/view.tsx +++ b/src/renderer/components/+user-management/+cluster-role-bindings/view.tsx @@ -24,7 +24,6 @@ import "./view.scss"; import { observer } from "mobx-react"; import React from "react"; import type { RouteComponentProps } from "react-router"; -import type { ClusterRoleBinding } from "../../../api/endpoints"; import { KubeObjectListLayout } from "../../kube-object"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { ClusterRoleBindingDialog } from "./dialog"; @@ -55,13 +54,13 @@ export class ClusterRoleBindings extends React.Component { store={clusterRoleBindingsStore} dependentStores={[clusterRolesStore, serviceAccountsStore]} sortingCallbacks={{ - [columnId.name]: (binding: ClusterRoleBinding) => binding.getName(), - [columnId.bindings]: (binding: ClusterRoleBinding) => binding.getSubjectNames(), - [columnId.age]: (binding: ClusterRoleBinding) => binding.getTimeDiffFromNow(), + [columnId.name]: binding => binding.getName(), + [columnId.bindings]: binding => binding.getSubjectNames(), + [columnId.age]: binding => binding.getTimeDiffFromNow(), }} searchFilters={[ - (binding: ClusterRoleBinding) => binding.getSearchFields(), - (binding: ClusterRoleBinding) => binding.getSubjectNames(), + binding => binding.getSearchFields(), + binding => binding.getSubjectNames(), ]} renderHeaderTitle="Cluster Role Bindings" renderTableHeader={[ @@ -70,7 +69,7 @@ export class ClusterRoleBindings extends React.Component { { title: "Bindings", className: "bindings", sortBy: columnId.bindings, id: columnId.bindings }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(binding: ClusterRoleBinding) => [ + renderTableContents={binding => [ binding.getName(), , binding.getSubjectNames(), diff --git a/src/renderer/components/+user-management/+cluster-roles/view.tsx b/src/renderer/components/+user-management/+cluster-roles/view.tsx index c58636e950..271802c10b 100644 --- a/src/renderer/components/+user-management/+cluster-roles/view.tsx +++ b/src/renderer/components/+user-management/+cluster-roles/view.tsx @@ -24,7 +24,6 @@ import "./view.scss"; import { observer } from "mobx-react"; import React from "react"; import type { RouteComponentProps } from "react-router"; -import type { ClusterRole } from "../../../api/endpoints"; import { KubeObjectListLayout } from "../../kube-object"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { AddClusterRoleDialog } from "./add-dialog"; @@ -51,11 +50,11 @@ export class ClusterRoles extends React.Component { className="ClusterRoles" store={clusterRolesStore} sortingCallbacks={{ - [columnId.name]: (clusterRole: ClusterRole) => clusterRole.getName(), - [columnId.age]: (clusterRole: ClusterRole) => clusterRole.getTimeDiffFromNow(), + [columnId.name]: clusterRole => clusterRole.getName(), + [columnId.age]: clusterRole => clusterRole.getTimeDiffFromNow(), }} searchFilters={[ - (clusterRole: ClusterRole) => clusterRole.getSearchFields(), + clusterRole => clusterRole.getSearchFields(), ]} renderHeaderTitle="Cluster Roles" renderTableHeader={[ @@ -63,7 +62,7 @@ export class ClusterRoles extends React.Component { { className: "warning", showWithColumn: columnId.name }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(clusterRole: ClusterRole) => [ + renderTableContents={clusterRole => [ clusterRole.getName(), , clusterRole.getAge(), diff --git a/src/renderer/components/+user-management/+role-bindings/view.tsx b/src/renderer/components/+user-management/+role-bindings/view.tsx index fa32c599d6..247e72482c 100644 --- a/src/renderer/components/+user-management/+role-bindings/view.tsx +++ b/src/renderer/components/+user-management/+role-bindings/view.tsx @@ -23,7 +23,6 @@ import "./view.scss"; import { observer } from "mobx-react"; import React from "react"; import type { RouteComponentProps } from "react-router"; -import type { RoleBinding } from "../../../api/endpoints"; import { KubeObjectListLayout } from "../../kube-object"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { RoleBindingDialog } from "./dialog"; @@ -55,14 +54,14 @@ export class RoleBindings extends React.Component { store={roleBindingsStore} dependentStores={[rolesStore, clusterRolesStore, serviceAccountsStore]} sortingCallbacks={{ - [columnId.name]: (binding: RoleBinding) => binding.getName(), - [columnId.namespace]: (binding: RoleBinding) => binding.getNs(), - [columnId.bindings]: (binding: RoleBinding) => binding.getSubjectNames(), - [columnId.age]: (binding: RoleBinding) => binding.getTimeDiffFromNow(), + [columnId.name]: binding => binding.getName(), + [columnId.namespace]: binding => binding.getNs(), + [columnId.bindings]: binding => binding.getSubjectNames(), + [columnId.age]: binding => binding.getTimeDiffFromNow(), }} searchFilters={[ - (binding: RoleBinding) => binding.getSearchFields(), - (binding: RoleBinding) => binding.getSubjectNames(), + binding => binding.getSearchFields(), + binding => binding.getSubjectNames(), ]} renderHeaderTitle="Role Bindings" renderTableHeader={[ @@ -72,7 +71,7 @@ export class RoleBindings extends React.Component { { title: "Bindings", className: "bindings", sortBy: columnId.bindings, id: columnId.bindings }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(binding: RoleBinding) => [ + renderTableContents={binding => [ binding.getName(), , binding.getNs(), diff --git a/src/renderer/components/+user-management/+roles/view.tsx b/src/renderer/components/+user-management/+roles/view.tsx index b6894b0571..dd71c83b93 100644 --- a/src/renderer/components/+user-management/+roles/view.tsx +++ b/src/renderer/components/+user-management/+roles/view.tsx @@ -24,7 +24,6 @@ import "./view.scss"; import { observer } from "mobx-react"; import React from "react"; import type { RouteComponentProps } from "react-router"; -import type { Role } from "../../../api/endpoints"; import { KubeObjectListLayout } from "../../kube-object"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; import { AddRoleDialog } from "./add-dialog"; @@ -51,12 +50,12 @@ export class Roles extends React.Component { className="Roles" store={rolesStore} sortingCallbacks={{ - [columnId.name]: (role: Role) => role.getName(), - [columnId.namespace]: (role: Role) => role.getNs(), - [columnId.age]: (role: Role) => role.getTimeDiffFromNow(), + [columnId.name]: role => role.getName(), + [columnId.namespace]: role => role.getNs(), + [columnId.age]: role => role.getTimeDiffFromNow(), }} searchFilters={[ - (role: Role) => role.getSearchFields(), + role => role.getSearchFields(), ]} renderHeaderTitle="Roles" renderTableHeader={[ @@ -65,7 +64,7 @@ export class Roles extends React.Component { { title: "Namespace", className: "namespace", sortBy: columnId.namespace, id: columnId.namespace }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(role: Role) => [ + renderTableContents={role => [ role.getName(), , role.getNs(), diff --git a/src/renderer/components/+user-management/+service-accounts/view.tsx b/src/renderer/components/+user-management/+service-accounts/view.tsx index 65798af192..c8bdaaa656 100644 --- a/src/renderer/components/+user-management/+service-accounts/view.tsx +++ b/src/renderer/components/+user-management/+service-accounts/view.tsx @@ -54,12 +54,12 @@ export class ServiceAccounts extends React.Component { tableId="access_service_accounts" className="ServiceAccounts" store={serviceAccountsStore} sortingCallbacks={{ - [columnId.name]: (account: ServiceAccount) => account.getName(), - [columnId.namespace]: (account: ServiceAccount) => account.getNs(), - [columnId.age]: (account: ServiceAccount) => account.getTimeDiffFromNow(), + [columnId.name]: account => account.getName(), + [columnId.namespace]: account => account.getNs(), + [columnId.age]: account => account.getTimeDiffFromNow(), }} searchFilters={[ - (account: ServiceAccount) => account.getSearchFields(), + account => account.getSearchFields(), ]} renderHeaderTitle="Service Accounts" renderTableHeader={[ @@ -68,7 +68,7 @@ export class ServiceAccounts extends React.Component { { title: "Namespace", className: "namespace", sortBy: columnId.namespace, id: columnId.namespace }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(account: ServiceAccount) => [ + renderTableContents={account => [ account.getName(), , account.getNs(), diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx index 0e2f98d16a..6938185479 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx @@ -31,7 +31,7 @@ import { Notifications } from "../notifications"; import { cssNames } from "../../utils"; import { Input } from "../input"; import { systemName, maxLength } from "../input/input_validators"; -import type { IKubeObjectMetadata } from "../../api/kube-object"; +import type { KubeObjectMetadata } from "../../api/kube-object"; interface Props extends Partial { } @@ -104,7 +104,7 @@ export class CronJobTriggerDialog extends Component { name: cronjob.metadata.name, uid: cronjob.metadata.uid, }], - } as IKubeObjectMetadata + } as KubeObjectMetadata }); close(); diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index b1c5e3424c..8dca609361 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -62,20 +62,20 @@ export class CronJobs extends React.Component { className="CronJobs" store={cronJobStore} dependentStores={[jobStore, eventStore]} sortingCallbacks={{ - [columnId.name]: (cronJob: CronJob) => cronJob.getName(), - [columnId.namespace]: (cronJob: CronJob) => cronJob.getNs(), - [columnId.suspend]: (cronJob: CronJob) => cronJob.getSuspendFlag(), - [columnId.active]: (cronJob: CronJob) => cronJobStore.getActiveJobsNum(cronJob), - [columnId.lastSchedule]: (cronJob: CronJob) => ( + [columnId.name]: cronJob => cronJob.getName(), + [columnId.namespace]: cronJob => cronJob.getNs(), + [columnId.suspend]: cronJob => cronJob.getSuspendFlag(), + [columnId.active]: cronJob => cronJobStore.getActiveJobsNum(cronJob), + [columnId.lastSchedule]: cronJob => ( cronJob.status?.lastScheduleTime ? moment().diff(cronJob.status.lastScheduleTime) : 0 ), - [columnId.age]: (cronJob: CronJob) => cronJob.getTimeDiffFromNow(), + [columnId.age]: cronJob => cronJob.getTimeDiffFromNow(), }} searchFilters={[ - (cronJob: CronJob) => cronJob.getSearchFields(), - (cronJob: CronJob) => cronJob.getSchedule(), + cronJob => cronJob.getSearchFields(), + cronJob => cronJob.getSchedule(), ]} renderHeaderTitle="Cron Jobs" renderTableHeader={[ @@ -88,7 +88,7 @@ export class CronJobs extends React.Component { { title: "Last schedule", className: "last-schedule", sortBy: columnId.lastSchedule, id: columnId.lastSchedule }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(cronJob: CronJob) => [ + renderTableContents={cronJob => [ cronJob.getName(), , cronJob.getNs(), diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx index e22c310e3d..63f04a8049 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx @@ -65,14 +65,14 @@ export class DaemonSets extends React.Component { className="DaemonSets" store={daemonSetStore} dependentStores={[podsStore, nodesStore, eventStore]} sortingCallbacks={{ - [columnId.name]: (daemonSet: DaemonSet) => daemonSet.getName(), - [columnId.namespace]: (daemonSet: DaemonSet) => daemonSet.getNs(), - [columnId.pods]: (daemonSet: DaemonSet) => this.getPodsLength(daemonSet), - [columnId.age]: (daemonSet: DaemonSet) => daemonSet.getTimeDiffFromNow(), + [columnId.name]: daemonSet => daemonSet.getName(), + [columnId.namespace]: daemonSet => daemonSet.getNs(), + [columnId.pods]: daemonSet => this.getPodsLength(daemonSet), + [columnId.age]: daemonSet => daemonSet.getTimeDiffFromNow(), }} searchFilters={[ - (daemonSet: DaemonSet) => daemonSet.getSearchFields(), - (daemonSet: DaemonSet) => daemonSet.getLabels(), + daemonSet => daemonSet.getSearchFields(), + daemonSet => daemonSet.getLabels(), ]} renderHeaderTitle="Daemon Sets" renderTableHeader={[ @@ -83,7 +83,7 @@ export class DaemonSets extends React.Component { { title: "Node Selector", className: "labels", id: columnId.labels }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(daemonSet: DaemonSet) => [ + renderTableContents={daemonSet => [ daemonSet.getName(), daemonSet.getNs(), this.getPodsLength(daemonSet), diff --git a/src/renderer/components/+workloads-deployments/deployments.tsx b/src/renderer/components/+workloads-deployments/deployments.tsx index c07dc397cc..d43670f6e7 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -81,15 +81,15 @@ export class Deployments extends React.Component { className="Deployments" store={deploymentStore} dependentStores={[replicaSetStore, podsStore, nodesStore, eventStore]} sortingCallbacks={{ - [columnId.name]: (deployment: Deployment) => deployment.getName(), - [columnId.namespace]: (deployment: Deployment) => deployment.getNs(), - [columnId.replicas]: (deployment: Deployment) => deployment.getReplicas(), - [columnId.age]: (deployment: Deployment) => deployment.getTimeDiffFromNow(), - [columnId.condition]: (deployment: Deployment) => deployment.getConditionsText(), + [columnId.name]: deployment => deployment.getName(), + [columnId.namespace]: deployment => deployment.getNs(), + [columnId.replicas]: deployment => deployment.getReplicas(), + [columnId.age]: deployment => deployment.getTimeDiffFromNow(), + [columnId.condition]: deployment => deployment.getConditionsText(), }} searchFilters={[ - (deployment: Deployment) => deployment.getSearchFields(), - (deployment: Deployment) => deployment.getConditionsText(), + deployment => deployment.getSearchFields(), + deployment => deployment.getConditionsText(), ]} renderHeaderTitle="Deployments" renderTableHeader={[ @@ -101,7 +101,7 @@ export class Deployments extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Conditions", className: "conditions", sortBy: columnId.condition, id: columnId.condition }, ]} - renderTableContents={(deployment: Deployment) => [ + renderTableContents={deployment => [ deployment.getName(), , deployment.getNs(), @@ -110,9 +110,7 @@ export class Deployments extends React.Component { deployment.getAge(), this.renderConditions(deployment), ]} - renderItemMenu={(item: Deployment) => { - return ; - }} + renderItemMenu={item => } /> ); } diff --git a/src/renderer/components/+workloads-jobs/jobs.tsx b/src/renderer/components/+workloads-jobs/jobs.tsx index 9d0c46764f..e2640db6f6 100644 --- a/src/renderer/components/+workloads-jobs/jobs.tsx +++ b/src/renderer/components/+workloads-jobs/jobs.tsx @@ -27,7 +27,6 @@ import type { RouteComponentProps } from "react-router"; import { podsStore } from "../+workloads-pods/pods.store"; import { jobStore } from "./job.store"; import { eventStore } from "../+events/event.store"; -import type { Job } from "../../api/endpoints/job.api"; import { KubeObjectListLayout } from "../kube-object"; import kebabCase from "lodash/kebabCase"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; @@ -54,13 +53,13 @@ export class Jobs extends React.Component { className="Jobs" store={jobStore} dependentStores={[podsStore, eventStore]} sortingCallbacks={{ - [columnId.name]: (job: Job) => job.getName(), - [columnId.namespace]: (job: Job) => job.getNs(), - [columnId.conditions]: (job: Job) => job.getCondition() != null ? job.getCondition().type : "", - [columnId.age]: (job: Job) => job.getTimeDiffFromNow(), + [columnId.name]: job => job.getName(), + [columnId.namespace]: job => job.getNs(), + [columnId.conditions]: job => job.getCondition() != null ? job.getCondition().type : "", + [columnId.age]: job => job.getTimeDiffFromNow(), }} searchFilters={[ - (job: Job) => job.getSearchFields(), + job => job.getSearchFields(), ]} renderHeaderTitle="Jobs" renderTableHeader={[ @@ -71,7 +70,7 @@ export class Jobs extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Conditions", className: "conditions", sortBy: columnId.conditions, id: columnId.conditions }, ]} - renderTableContents={(job: Job) => { + renderTableContents={job => { const condition = job.getCondition(); return [ diff --git a/src/renderer/components/+workloads-overview/overview-statuses.tsx b/src/renderer/components/+workloads-overview/overview-statuses.tsx index ae67d96667..ebf62c1d98 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -47,7 +47,12 @@ const resources: KubeResource[] = [ export class OverviewStatuses extends React.Component { @boundMethod renderWorkload(resource: KubeResource): React.ReactElement { - const store = workloadStores[resource]; + const store = workloadStores.get(resource); + + if (!store) { + return null; + } + const items = store.getAllByNs(namespaceStore.contextNamespaces); return ( diff --git a/src/renderer/components/+workloads-pods/pod-tolerations.tsx b/src/renderer/components/+workloads-pods/pod-tolerations.tsx index 9fdaef1c81..28793e0ea5 100644 --- a/src/renderer/components/+workloads-pods/pod-tolerations.tsx +++ b/src/renderer/components/+workloads-pods/pod-tolerations.tsx @@ -38,13 +38,6 @@ enum sortBy { Value = "value", } -const sortingCallbacks = { - [sortBy.Key]: (toleration: IToleration) => toleration.key, - [sortBy.Operator]: (toleration: IToleration) => toleration.operator, - [sortBy.Effect]: (toleration: IToleration) => toleration.effect, - [sortBy.Seconds]: (toleration: IToleration) => toleration.tolerationSeconds, -}; - const getTableRow = (toleration: IToleration) => { const { key, operator, effect, tolerationSeconds, value } = toleration; @@ -68,10 +61,17 @@ export function PodTolerations({ tolerations }: Props) { toleration.key, + [sortBy.Operator]: toleration => toleration.operator, + [sortBy.Effect]: toleration => toleration.effect, + [sortBy.Seconds]: toleration => toleration.tolerationSeconds, + }} sortSyncWithUrl={false} className="PodTolerations" + renderRow={getTableRow} > Key @@ -80,9 +80,6 @@ export function PodTolerations({ tolerations }: Props) { Effect Seconds - { - tolerations.map(getTableRow) - }
); } diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index d7ef7175e8..b91a8a98e8 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -97,21 +97,21 @@ export class Pods extends React.Component { tableId = "workloads_pods" isConfigurable sortingCallbacks={{ - [columnId.name]: (pod: Pod) => pod.getName(), - [columnId.namespace]: (pod: Pod) => pod.getNs(), - [columnId.containers]: (pod: Pod) => pod.getContainers().length, - [columnId.restarts]: (pod: Pod) => pod.getRestartsCount(), - [columnId.owners]: (pod: Pod) => pod.getOwnerRefs().map(ref => ref.kind), - [columnId.qos]: (pod: Pod) => pod.getQosClass(), - [columnId.node]: (pod: Pod) => pod.getNodeName(), - [columnId.age]: (pod: Pod) => pod.getTimeDiffFromNow(), - [columnId.status]: (pod: Pod) => pod.getStatusMessage(), + [columnId.name]: pod => pod.getName(), + [columnId.namespace]: pod => pod.getNs(), + [columnId.containers]: pod => pod.getContainers().length, + [columnId.restarts]: pod => pod.getRestartsCount(), + [columnId.owners]: pod => pod.getOwnerRefs().map(ref => ref.kind), + [columnId.qos]: pod => pod.getQosClass(), + [columnId.node]: pod => pod.getNodeName(), + [columnId.age]: pod => pod.getTimeDiffFromNow(), + [columnId.status]: pod => pod.getStatusMessage(), }} searchFilters={[ - (pod: Pod) => pod.getSearchFields(), - (pod: Pod) => pod.getStatusMessage(), - (pod: Pod) => pod.status.podIP, - (pod: Pod) => pod.getNodeName(), + pod => pod.getSearchFields(), + pod => pod.getStatusMessage(), + pod => pod.status.podIP, + pod => pod.getNodeName(), ]} renderHeaderTitle="Pods" renderTableHeader={[ @@ -126,7 +126,7 @@ export class Pods extends React.Component { { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} - renderTableContents={(pod: Pod) => [ + renderTableContents={pod => [ , , pod.getNs(), diff --git a/src/renderer/components/+workloads-replicasets/replicasets.tsx b/src/renderer/components/+workloads-replicasets/replicasets.tsx index 51d63fec55..447280899f 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.tsx +++ b/src/renderer/components/+workloads-replicasets/replicasets.tsx @@ -55,15 +55,15 @@ export class ReplicaSets extends React.Component { tableId="workload_replicasets" className="ReplicaSets" store={replicaSetStore} sortingCallbacks={{ - [columnId.name]: (replicaSet: ReplicaSet) => replicaSet.getName(), - [columnId.namespace]: (replicaSet: ReplicaSet) => replicaSet.getNs(), - [columnId.desired]: (replicaSet: ReplicaSet) => replicaSet.getDesired(), - [columnId.current]: (replicaSet: ReplicaSet) => replicaSet.getCurrent(), - [columnId.ready]: (replicaSet: ReplicaSet) => replicaSet.getReady(), - [columnId.age]: (replicaSet: ReplicaSet) => replicaSet.getTimeDiffFromNow(), + [columnId.name]: replicaSet => replicaSet.getName(), + [columnId.namespace]: replicaSet => replicaSet.getNs(), + [columnId.desired]: replicaSet => replicaSet.getDesired(), + [columnId.current]: replicaSet => replicaSet.getCurrent(), + [columnId.ready]: replicaSet => replicaSet.getReady(), + [columnId.age]: replicaSet => replicaSet.getTimeDiffFromNow(), }} searchFilters={[ - (replicaSet: ReplicaSet) => replicaSet.getSearchFields(), + replicaSet => replicaSet.getSearchFields(), ]} renderHeaderTitle="Replica Sets" renderTableHeader={[ @@ -75,7 +75,7 @@ export class ReplicaSets extends React.Component { { title: "Ready", className: "ready", sortBy: columnId.ready, id: columnId.ready }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(replicaSet: ReplicaSet) => [ + renderTableContents={replicaSet => [ replicaSet.getName(), , replicaSet.getNs(), diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx index 82b1fff151..ff6441f33a 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx @@ -64,13 +64,13 @@ export class StatefulSets extends React.Component { className="StatefulSets" store={statefulSetStore} dependentStores={[podsStore, nodesStore, eventStore]} sortingCallbacks={{ - [columnId.name]: (statefulSet: StatefulSet) => statefulSet.getName(), - [columnId.namespace]: (statefulSet: StatefulSet) => statefulSet.getNs(), - [columnId.age]: (statefulSet: StatefulSet) => statefulSet.getTimeDiffFromNow(), - [columnId.replicas]: (statefulSet: StatefulSet) => statefulSet.getReplicas(), + [columnId.name]: statefulSet => statefulSet.getName(), + [columnId.namespace]: statefulSet => statefulSet.getNs(), + [columnId.age]: statefulSet => statefulSet.getTimeDiffFromNow(), + [columnId.replicas]: statefulSet => statefulSet.getReplicas(), }} searchFilters={[ - (statefulSet: StatefulSet) => statefulSet.getSearchFields(), + statefulSet => statefulSet.getSearchFields(), ]} renderHeaderTitle="Stateful Sets" renderTableHeader={[ @@ -81,7 +81,7 @@ export class StatefulSets extends React.Component { { className: "warning", showWithColumn: columnId.replicas }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={(statefulSet: StatefulSet) => [ + renderTableContents={statefulSet => [ statefulSet.getName(), statefulSet.getNs(), this.renderPods(statefulSet), @@ -89,9 +89,7 @@ export class StatefulSets extends React.Component { , statefulSet.getAge(), ]} - renderItemMenu={(item: StatefulSet) => { - return ; - }} + renderItemMenu={item => } /> ); } diff --git a/src/renderer/components/+workloads/workloads.stores.ts b/src/renderer/components/+workloads/workloads.stores.ts index a06c17200d..e53ea7cb03 100644 --- a/src/renderer/components/+workloads/workloads.stores.ts +++ b/src/renderer/components/+workloads/workloads.stores.ts @@ -28,13 +28,14 @@ import { jobStore } from "../+workloads-jobs/job.store"; import { cronJobStore } from "../+workloads-cronjobs/cronjob.store"; import type { KubeResource } from "../../../common/rbac"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; +import type { KubeObject } from "../../api/kube-object"; -export const workloadStores: Partial> = { - "pods": podsStore, - "deployments": deploymentStore, - "daemonsets": daemonSetStore, - "statefulsets": statefulSetStore, - "replicasets": replicaSetStore, - "jobs": jobStore, - "cronjobs": cronJobStore, -}; +export const workloadStores = new Map>([ + ["pods", podsStore], + ["deployments", deploymentStore], + ["daemonsets", daemonSetStore], + ["statefulsets", statefulSetStore], + ["replicasets", replicaSetStore], + ["jobs", jobStore], + ["cronjobs", cronJobStore], +]); diff --git a/src/renderer/components/dock/edit-resource.store.ts b/src/renderer/components/dock/edit-resource.store.ts index 7931d86451..c0467b330b 100644 --- a/src/renderer/components/dock/edit-resource.store.ts +++ b/src/renderer/components/dock/edit-resource.store.ts @@ -84,7 +84,7 @@ export class EditResourceStore extends DockTabStore { return Boolean(tabDataReady && this.getResource(tabId)); // ready to edit resource } - getStore(tabId: TabId): KubeObjectStore | undefined { + getStore(tabId: TabId): KubeObjectStore | undefined { return apiManager.getStore(this.getResourcePath(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 72dafbd90e..1287312653 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -26,7 +26,7 @@ import React, { ReactNode } from "react"; import { computed, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { ConfirmDialog, ConfirmDialogParams } from "../confirm-dialog"; -import { Table, TableCell, TableCellProps, TableHead, TableProps, TableRow, TableRowProps, TableSortCallback } from "../table"; +import { Table, TableCell, TableCellProps, TableHead, TableProps, TableRow, TableRowProps, TableSortCallbacks } from "../table"; import { boundMethod, createStorage, cssNames, IClassName, isReactNode, noop, ObservableToggleSet, prevDefault, stopPropagation } from "../../utils"; import { AddRemoveButtons, AddRemoveButtonsProps } from "../add-remove-buttons"; import { NoItems } from "../no-items"; @@ -44,8 +44,10 @@ import { namespaceStore } from "../+namespaces/namespace.store"; -export type SearchFilter = (item: T) => string | number | (string | number)[]; -export type ItemsFilter = (items: T[]) => T[]; +export type SearchFilter = (item: I) => string | number | (string | number)[]; +export type SearchFilters = Record>; +export type ItemsFilter = (items: I[]) => I[]; +export type ItemsFilters = Record>; export interface HeaderPlaceholders { title?: ReactNode; @@ -55,23 +57,22 @@ export interface HeaderPlaceholders { } export type HeaderCustomizer = (placeholders: HeaderPlaceholders) => HeaderPlaceholders; - -export interface ItemListLayoutProps { +export interface ItemListLayoutProps { tableId?: string; className: IClassName; - items?: T[]; - store: ItemStore; - dependentStores?: ItemStore[]; + items?: I[]; + store: ItemStore; + dependentStores?: ItemStore[]; preloadStores?: boolean; hideFilters?: boolean; - searchFilters?: SearchFilter[]; + searchFilters?: SearchFilter[]; /** @deprecated */ - filterItems?: ItemsFilter[]; + filterItems?: ItemsFilter[]; // header (title, filtering, searching, etc.) showHeader?: boolean; headerClassName?: IClassName; - renderHeaderTitle?: ReactNode | ((parent: ItemListLayout) => ReactNode); + renderHeaderTitle?: ReactNode | ((parent: ItemListLayout) => ReactNode); customizeHeader?: HeaderCustomizer | HeaderCustomizer[]; // items list configuration @@ -79,26 +80,28 @@ export interface ItemListLayoutProps { isSelectable?: boolean; // show checkbox in rows for selecting items isConfigurable?: boolean; copyClassNameFromHeadCells?: boolean; - sortingCallbacks?: { [sortBy: string]: TableSortCallback }; - tableProps?: Partial; // low-level table configuration + sortingCallbacks?: TableSortCallbacks; + tableProps?: Partial>; // low-level table configuration renderTableHeader: TableCellProps[] | null; - renderTableContents: (item: T) => (ReactNode | TableCellProps)[]; - renderItemMenu?: (item: T, store: ItemStore) => ReactNode; - customizeTableRowProps?: (item: T) => Partial; + renderTableContents: (item: I) => (ReactNode | TableCellProps)[]; + renderItemMenu?: (item: I, store: ItemStore) => ReactNode; + customizeTableRowProps?: (item: I) => Partial; addRemoveButtons?: Partial; virtual?: boolean; // item details view hasDetailsView?: boolean; - detailsItem?: T; - onDetails?: (item: T) => void; + detailsItem?: I; + onDetails?: (item: I) => void; // other - customizeRemoveDialog?: (selectedItems: T[]) => Partial; - renderFooter?: (parent: ItemListLayout) => React.ReactNode; + customizeRemoveDialog?: (selectedItems: I[]) => Partial; + renderFooter?: (parent: ItemListLayout) => React.ReactNode; + + filterCallbacks?: ItemsFilters; } -const defaultProps: Partial = { +const defaultProps: Partial> = { showHeader: true, isSelectable: true, isConfigurable: false, @@ -115,14 +118,14 @@ const defaultProps: Partial = { }; @observer -export class ItemListLayout extends React.Component { +export class ItemListLayout extends React.Component> { static defaultProps = defaultProps as object; private storage = createStorage("item_list_layout", { showFilters: false, // setup defaults }); - constructor(props: ItemListLayoutProps) { + constructor(props: ItemListLayoutProps) { super(props); makeObservable(this); } @@ -158,7 +161,7 @@ export class ItemListLayout extends React.Component { stores.forEach(store => store.loadAll(namespaceStore.contextNamespaces)); } - private filterCallbacks: { [type: string]: ItemsFilter } = { + private filterCallbacks: ItemsFilters = { [FilterType.SEARCH]: items => { const { searchFilters } = this.props; const search = pageFilters.getValues(FilterType.SEARCH)[0] || ""; @@ -199,20 +202,20 @@ export class ItemListLayout extends React.Component { return activeFilters; } - applyFilters(filters: ItemsFilter[], items: T[]): T[] { + applyFilters(filters: ItemsFilter[], items: I[]): I[] { if (!filters || !filters.length) return items; return filters.reduce((items, filter) => filter(items), items); } @computed get items() { - const { filters, filterCallbacks } = this; + const { filters, filterCallbacks, props } = this; const filterGroups = groupBy(filters, ({ type }) => type); - const filterItems: ItemsFilter[] = []; + const filterItems: ItemsFilter[] = []; Object.entries(filterGroups).forEach(([type, filtersGroup]) => { - const filterCallback = filterCallbacks[type]; + const filterCallback = filterCallbacks[type] ?? props.filterCallbacks?.[type]; if (filterCallback && filtersGroup.length > 0) { filterItems.push(filterCallback); diff --git a/src/renderer/components/kube-object/kube-object-details.tsx b/src/renderer/components/kube-object/kube-object-details.tsx index 4075361368..7ef8686130 100644 --- a/src/renderer/components/kube-object/kube-object-details.tsx +++ b/src/renderer/components/kube-object/kube-object-details.tsx @@ -30,9 +30,7 @@ import type { KubeObject } from "../../api/kube-object"; import { Spinner } from "../spinner"; import { apiManager } from "../../api/api-manager"; import { crdStore } from "../+custom-resources/crd.store"; -import { CrdResourceDetails } from "../+custom-resources"; import { KubeObjectMenu } from "./kube-object-menu"; -import type { CustomResourceDefinition } from "../../api/endpoints"; import { KubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import logger from "../../../main/logger"; @@ -108,6 +106,8 @@ export class KubeObjectDetails extends React.Component { ?.getByPath(this.path); } catch (error) { logger.error(`[KUBE-OBJECT-DETAILS]: failed to get store or object: ${error}`, { path: this.path }); + + return undefined; } } @@ -142,7 +142,7 @@ export class KubeObjectDetails extends React.Component { }); render() { - const { object, isLoading, loadingError, isCrdInstance } = this; + const { object, isLoading, loadingError } = this; const isOpen = !!(object || isLoading || loadingError); if (!object) { @@ -169,10 +169,6 @@ export class KubeObjectDetails extends React.Component { )); - if (isCrdInstance && details.length === 0) { - details.push(); - } - return ( extends ItemListLayoutProps { + store: KubeObjectStore; + dependentStores?: KubeObjectStore[]; } -const defaultProps: Partial = { +const defaultProps: Partial> = { onDetails: (item: KubeObject) => showDetails(item.selfLink), }; @observer -export class KubeObjectListLayout extends React.Component { +export class KubeObjectListLayout extends React.Component> { static defaultProps = defaultProps as object; - constructor(props: KubeObjectListLayoutProps) { + constructor(props: KubeObjectListLayoutProps) { super(props); makeObservable(this); } @@ -95,7 +95,7 @@ export class KubeObjectListLayout extends React.Component } // safe because we are dealing with KubeObjects here + renderItemMenu={item => } /> ); } diff --git a/src/renderer/components/kube-object/kube-object-meta.tsx b/src/renderer/components/kube-object/kube-object-meta.tsx index 98eb539720..f41b3d0991 100644 --- a/src/renderer/components/kube-object/kube-object-meta.tsx +++ b/src/renderer/components/kube-object/kube-object-meta.tsx @@ -20,7 +20,7 @@ */ import React from "react"; -import type { IKubeMetaField, KubeObject } from "../../api/kube-object"; +import type { KubeMetaField, KubeObject } from "../../api/kube-object"; import { DrawerItem, DrawerItemLabels } from "../drawer"; import { lookupApiLink } from "../../api/kube-api"; import { Link } from "react-router-dom"; @@ -30,15 +30,15 @@ import { getDetailsUrl } from "./kube-object-details"; export interface KubeObjectMetaProps { object: KubeObject; - hideFields?: IKubeMetaField[]; + hideFields?: KubeMetaField[]; } export class KubeObjectMeta extends React.Component { - static defaultHiddenFields: IKubeMetaField[] = [ + static defaultHiddenFields: KubeMetaField[] = [ "uid", "resourceVersion", "selfLink" ]; - isHidden(field: IKubeMetaField): boolean { + isHidden(field: KubeMetaField): boolean { const { hideFields = KubeObjectMeta.defaultHiddenFields } = this.props; return hideFields.includes(field); diff --git a/src/renderer/components/table/table.tsx b/src/renderer/components/table/table.tsx index c1cc7f0cd6..bb5e63f570 100644 --- a/src/renderer/components/table/table.tsx +++ b/src/renderer/components/table/table.tsx @@ -30,19 +30,18 @@ import { TableHead, TableHeadElem, TableHeadProps } from "./table-head"; import type { TableCellElem } from "./table-cell"; import { VirtualList } from "../virtual-list"; import { createPageParam } from "../../navigation"; -import type { ItemObject } from "../../item.store"; import { getSortParams, setSortParams } from "./table.storage"; import { computed, makeObservable } from "mobx"; export type TableSortBy = string; export type TableOrderBy = "asc" | "desc" | string; export type TableSortParams = { sortBy: TableSortBy; orderBy: TableOrderBy }; -export type TableSortCallback = (data: D) => string | number | (string | number)[]; -export type TableSortCallbacks = { [columnId: string]: TableSortCallback }; +export type TableSortCallback = (data: Item) => string | number | (string | number)[]; +export type TableSortCallbacks = Record>; -export interface TableProps extends React.DOMAttributes { +export interface TableProps extends React.DOMAttributes { tableId?: string; - items?: ItemObject[]; // Raw items data + items?: Item[]; // Raw items data className?: string; autoSize?: boolean; // Setup auto-sizing for all columns (flex: 1 0) selectable?: boolean; // Highlight rows on hover @@ -52,7 +51,7 @@ export interface TableProps extends React.DOMAttributes { * Define sortable callbacks for every column in * @sortItem argument in the callback is an object, provided in */ - sortable?: TableSortCallbacks; + sortable?: TableSortCallbacks; sortSyncWithUrl?: boolean; // sorting state is managed globally from url params sortByDefault?: Partial; // default sorting params onSort?: (params: TableSortParams) => void; // callback on sort change, default: global sync with url @@ -61,8 +60,9 @@ export interface TableProps extends React.DOMAttributes { virtual?: boolean; // Use virtual list component to render only visible rows rowPadding?: string; rowLineHeight?: string; - customRowHeights?: (item: object, lineHeight: number, paddings: number) => number; + customRowHeights?: (item: Item, lineHeight: number, paddings: number) => number; getTableRow?: (uid: string) => React.ReactElement; + renderRow?: (item: Item) => React.ReactElement; } export const sortByUrlParam = createPageParam({ @@ -74,8 +74,8 @@ export const orderByUrlParam = createPageParam({ }); @observer -export class Table extends React.Component { - static defaultProps: TableProps = { +export class Table extends React.Component> { + static defaultProps: TableProps = { scrollable: true, autoSize: true, rowPadding: "8px", @@ -83,7 +83,7 @@ export class Table extends React.Component { sortSyncWithUrl: true, }; - constructor(props: TableProps) { + constructor(props: TableProps) { super(props); makeObservable(this); } @@ -171,9 +171,20 @@ export class Table extends React.Component { }); } - renderRows() { - const { sortable, noItems, children, virtual, customRowHeights, rowLineHeight, rowPadding, items, getTableRow, selectedItemId, className } = this.props; + private getContent() { + const { items, renderRow, children } = this.props; const content = React.Children.toArray(children) as (TableRowElem | TableHeadElem)[]; + + if (renderRow) { + content.push(...items.map(renderRow)); + } + + return content; + } + + renderRows() { + const { sortable, noItems, virtual, customRowHeights, rowLineHeight, rowPadding, items, getTableRow, selectedItemId, className } = this.props; + const content = this.getContent(); let rows: React.ReactElement[] = content.filter(elem => elem.type === TableRow); let sortedItems = rows.length ? rows.map(row => row.props.sortItem) : [...items]; diff --git a/src/renderer/initializers/kube-object-detail-registry.tsx b/src/renderer/initializers/kube-object-detail-registry.tsx index 56e88ac3d9..ddc7617f45 100644 --- a/src/renderer/initializers/kube-object-detail-registry.tsx +++ b/src/renderer/initializers/kube-object-detail-registry.tsx @@ -29,7 +29,7 @@ import { ConfigMapDetails } from "../components/+config-maps"; import { PodDisruptionBudgetDetails } from "../components/+config-pod-disruption-budgets"; import { ResourceQuotaDetails } from "../components/+config-resource-quotas"; import { SecretDetails } from "../components/+config-secrets"; -import { CRDDetails } from "../components/+custom-resources"; +import { CRDDetails, CrdResourceDetails } from "../components/+custom-resources"; import { EventDetails } from "../components/+events"; import { KubeEventDetails } from "../components/+events/kube-event-details"; import { NamespaceDetails } from "../components/+namespaces"; @@ -55,6 +55,7 @@ import { PodDetails } from "../components/+workloads-pods"; import { ReplicaSetDetails } from "../components/+workloads-replicasets"; import { StatefulSetDetails } from "../components/+workloads-statefulsets"; import type { KubeObjectDetailsProps } from "../components/kube-object"; +import type { CustomResourceDefinition } from "../api/endpoints"; export function intiKubeObjectDetailRegistry() { KubeObjectDetailRegistry.getInstance() @@ -444,6 +445,13 @@ export function intiKubeObjectDetailRegistry() { components: { Details: (props: KubeObjectDetailsProps) => , } + }, + { + kind: "CustomResourceDefinition", + apiVersions: ["apiextensions.k8s.io/v1"], + components: { + Details: (props: KubeObjectDetailsProps) => , + } } ]); } diff --git a/src/renderer/item.store.ts b/src/renderer/item.store.ts index 0a72352649..2b5a736abd 100644 --- a/src/renderer/item.store.ts +++ b/src/renderer/item.store.ts @@ -28,15 +28,15 @@ export interface ItemObject { getName(): string; } -export abstract class ItemStore { - abstract loadAll(...args: any[]): Promise; +export abstract class ItemStore { + abstract loadAll(...args: any[]): Promise; - protected defaultSorting = (item: T) => item.getName(); + protected defaultSorting = (item: Item) => item.getName(); @observable failedLoading = false; @observable isLoading = false; @observable isLoaded = false; - @observable items = observable.array([], { deep: false }); + @observable items = observable.array([], { deep: false }); @observable selectedItemsIds = observable.map(); constructor() { @@ -44,11 +44,11 @@ export abstract class ItemStore { autoBind(this); } - @computed get selectedItems(): T[] { + @computed get selectedItems(): Item[] { return this.items.filter(item => this.selectedItemsIds.get(item.getId())); } - public getItems(): T[] { + public getItems(): Item[] { return Array.from(this.items); } @@ -56,8 +56,8 @@ export abstract class ItemStore { return this.items.length; } - getByName(name: string, ...args: any[]): T; - getByName(name: string): T { + getByName(name: string, ...args: any[]): Item; + getByName(name: string): Item { return this.items.find(item => item.getName() === name); } @@ -75,13 +75,13 @@ export abstract class ItemStore { * @param order whether to sort from least to greatest (`"asc"` (default)) or vice-versa (`"desc"`) */ @action - protected sortItems(items: T[] = this.items, sorting: ((item: T) => any)[] = [this.defaultSorting], order?: "asc" | "desc"): T[] { + protected sortItems(items: Item[] = this.items, sorting: ((item: Item) => any)[] = [this.defaultSorting], order?: "asc" | "desc"): Item[] { return orderBy(items, sorting, order); } protected async createItem(...args: any[]): Promise; @action - protected async createItem(request: () => Promise) { + protected async createItem(request: () => Promise) { const newItem = await request(); const item = this.items.find(item => item.getId() === newItem.getId()); @@ -98,7 +98,7 @@ export abstract class ItemStore { protected async loadItems(...args: any[]): Promise; @action - protected async loadItems(request: () => Promise, sortItems = true) { + protected async loadItems(request: () => Promise, sortItems = true) { if (this.isLoading) { await when(() => !this.isLoading); @@ -117,9 +117,9 @@ export abstract class ItemStore { } } - protected async loadItem(...args: any[]): Promise + protected async loadItem(...args: any[]): Promise @action - protected async loadItem(request: () => Promise, sortItems = true) { + protected async loadItem(request: () => Promise, sortItems = true) { const item = await Promise.resolve(request()).catch(() => null); if (item) { @@ -141,7 +141,7 @@ export abstract class ItemStore { } @action - protected async updateItem(item: T, request: () => Promise) { + protected async updateItem(item: Item, request: () => Promise) { const updatedItem = await request(); const index = this.items.findIndex(i => i.getId() === item.getId()); @@ -151,28 +151,28 @@ export abstract class ItemStore { } @action - protected async removeItem(item: T, request: () => Promise) { + protected async removeItem(item: Item, request: () => Promise) { await request(); this.items.remove(item); this.selectedItemsIds.delete(item.getId()); } - isSelected(item: T) { + isSelected(item: Item) { return !!this.selectedItemsIds.get(item.getId()); } @action - select(item: T) { + select(item: Item) { this.selectedItemsIds.set(item.getId(), true); } @action - unselect(item: T) { + unselect(item: Item) { this.selectedItemsIds.delete(item.getId()); } @action - toggleSelection(item: T) { + toggleSelection(item: Item) { if (this.isSelected(item)) { this.unselect(item); } else { @@ -181,7 +181,7 @@ export abstract class ItemStore { } @action - toggleSelectionAll(visibleItems: T[] = this.items) { + toggleSelectionAll(visibleItems: Item[] = this.items) { const allSelected = visibleItems.every(this.isSelected); if (allSelected) { @@ -191,7 +191,7 @@ export abstract class ItemStore { } } - isSelectedAll(visibleItems: T[] = this.items) { + isSelectedAll(visibleItems: Item[] = this.items) { if (!visibleItems.length) return false; return visibleItems.every(this.isSelected); diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index 881a9ae6f3..14dbbc6152 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -31,13 +31,13 @@ import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi, parseKubeApi } from import type { KubeJsonApiData } from "./api/kube-json-api"; import { Notifications } from "./components/notifications"; -export interface KubeObjectStoreLoadingParams { +export interface KubeObjectStoreLoadingParams { namespaces: string[]; - api?: KubeApi; + api?: KubeApi; reqInit?: RequestInit; } -export abstract class KubeObjectStore extends ItemStore { +export abstract class KubeObjectStore extends ItemStore { static defaultContext = observable.box(); // TODO: support multiple cluster contexts abstract api: KubeApi; @@ -137,7 +137,7 @@ export abstract class KubeObjectStore extends ItemSt } } - protected async loadItems({ namespaces, api, reqInit }: KubeObjectStoreLoadingParams): Promise { + protected async loadItems({ namespaces, api, reqInit }: KubeObjectStoreLoadingParams): Promise { if (this.context?.cluster.isAllowedResource(api.kind)) { if (!api.isNamespaced) { return api.list({ reqInit }, this.query); @@ -279,7 +279,7 @@ export abstract class KubeObjectStore extends ItemSt } async update(item: T, data: Partial): Promise { - const newItem = await item.update(data); + const newItem = await item.update(data); ensureObjectSelfLink(this.api, newItem); @@ -345,7 +345,7 @@ export abstract class KubeObjectStore extends ItemSt const { signal } = abortController; - const callback = (data: IKubeWatchEvent, error: any) => { + const callback = (data: IKubeWatchEvent, error: any) => { if (!this.isLoaded || error instanceof DOMException) return; if (error instanceof Response) { @@ -393,7 +393,7 @@ export abstract class KubeObjectStore extends ItemSt switch (type) { case "ADDED": case "MODIFIED": - const newItem = new api.objectConstructor(object); + const newItem = new api.objectConstructor(object) as T; if (!item) { items.push(newItem);