From 60a19143b49ccfed574ecd1ec328ba00ec09222a Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 7 Jun 2021 12:02:15 -0400 Subject: [PATCH] Revert 2844 (#2980) * Revert "review comments" This reverts commit 97f2ecd88de65fc754cc3679ab735963945ef4bc. * Revert "Switch to I, remove type parameter default" This reverts commit a3073cc99b1cdd85eb693d65bae99b2f7df4842d. * Revert "Improve Table typing and remove annotations on callbacks" This reverts commit defb0ea0dd0a2a5bdf648e56a75a8fdccf42397d. --- .../api/__tests__/api-manager.test.ts | 4 +- src/renderer/api/__tests__/kube-api.test.ts | 15 ++--- src/renderer/api/api-manager.ts | 21 ++++--- .../api/endpoints/resource-applier.api.ts | 4 +- src/renderer/api/kube-api.ts | 18 +++--- src/renderer/api/kube-object.ts | 6 +- 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 | 52 ++++++++--------- .../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 +++-- .../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 +++--- .../add-role-binding-dialog.tsx | 13 +++-- .../role-bindings.store.ts | 2 +- .../role-bindings.tsx | 15 ++--- .../+user-management-roles/roles.store.ts | 2 +- .../+user-management-roles/roles.tsx | 11 ++-- .../service-accounts.tsx | 10 ++-- .../+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 | 2 +- .../+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 | 58 +++++++++---------- .../kube-object/kube-object-details.tsx | 15 +++-- .../kube-object/kube-object-list-layout.tsx | 26 +++------ src/renderer/components/table/table.tsx | 35 ++++------- src/renderer/item.store.ts | 44 +++++++------- src/renderer/kube-object.store.ts | 19 +++--- 55 files changed, 471 insertions(+), 479 deletions(-) diff --git a/src/renderer/api/__tests__/api-manager.test.ts b/src/renderer/api/__tests__/api-manager.test.ts index 83034d20b6..8c7beb12c9 100644 --- a/src/renderer/api/__tests__/api-manager.test.ts +++ b/src/renderer/api/__tests__/api-manager.test.ts @@ -22,9 +22,8 @@ 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; @@ -37,7 +36,6 @@ 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__/kube-api.test.ts b/src/renderer/api/__tests__/kube-api.test.ts index 1eb0199f89..c7415cba73 100644 --- a/src/renderer/api/__tests__/kube-api.test.ts +++ b/src/renderer/api/__tests__/kube-api.test.ts @@ -20,7 +20,6 @@ */ import { KubeApi } from "../kube-api"; -import { KubeObject } from "../kube-object"; describe("KubeApi", () => { it("uses url from apiBase if apiBase contains the resource", async () => { @@ -30,7 +29,7 @@ describe("KubeApi", () => { body: JSON.stringify({ resources: [{ name: "ingresses" - }] as any[] + }] as any [] }) }; } else if (request.url === "/api-kube/apis/extensions/v1beta1") { @@ -39,13 +38,13 @@ describe("KubeApi", () => { body: JSON.stringify({ resources: [{ name: "ingresses" - }] as any[] + }] as any [] }) }; } else { return { body: JSON.stringify({ - resources: [] as any[] + resources: [] as any [] }) }; } @@ -54,7 +53,6 @@ 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, @@ -70,7 +68,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") { @@ -78,13 +76,13 @@ describe("KubeApi", () => { body: JSON.stringify({ resources: [{ name: "ingresses" - }] as any[] + }] as any [] }) }; } else { return { body: JSON.stringify({ - resources: [] as any[] + resources: [] as any [] }) }; } @@ -93,7 +91,6 @@ 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 03c85a248c..eafcf0d8ee 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -24,18 +24,17 @@ import type { KubeObjectStore } from "../kube-object.store"; import { action, observable, makeObservable } from "mobx"; import { autoBind } 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); } @@ -47,10 +46,10 @@ export class ApiManager { return Array.from(this.apis.values()).find((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); } }); @@ -59,13 +58,13 @@ export class ApiManager { } } - protected resolveApi(api: string | KubeApi): KubeApi { - if (typeof api === "string") return this.getApi(api) as KubeApi; + protected resolveApi(api: string | KubeApi): KubeApi { + if (typeof api === "string") return this.getApi(api); 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()); @@ -76,13 +75,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 | undefined { + getStore(api: string | KubeApi): S { 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 b10c10f7db..1756977c95 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[0] as K ?? null; + return items.length === 1 ? items[0] : items; }); } }; diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index ff023f51f2..21e370a207 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -49,7 +49,7 @@ export interface IKubeApiOptions { */ fallbackApiBases?: string[]; - objectConstructor: IKubeObjectConstructor; + objectConstructor?: IKubeObjectConstructor; request?: KubeJsonApi; isNamespaced?: boolean; kind?: string; @@ -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: KubeJsonA } } -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; @@ -152,7 +152,7 @@ export class KubeApi { constructor(protected options: IKubeApiOptions) { const { - objectConstructor, + objectConstructor = KubeObject as IKubeObjectConstructor, 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 b14fd3d993..b72beb9383 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -30,7 +30,7 @@ import type { JsonApiParams } from "./json-api"; import { resourceApplierApi } from "./endpoints/resource-applier.api"; import { hasOptionalProperty, hasTypedProperty, isObject, isString, bindPredicate, isTypedArray, isRecord } from "../../common/utils/type-narrowing"; -export type IKubeObjectConstructor = (new (data: KubeJsonApiData | any) => K) & { +export type IKubeObjectConstructor = (new (data: KubeJsonApiData | any) => T) & { kind?: string; namespaced?: boolean; apiBase?: string; @@ -266,8 +266,8 @@ export class KubeObject(data: Partial): Promise { - return resourceApplierApi.update({ + async update(data: Partial): Promise { + 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 4d316b5caa..1a0f7e0b17 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -31,9 +31,8 @@ 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; } @@ -59,11 +58,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[] = []; @@ -81,7 +80,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 0926130cb5..d8cb43a98d 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 => chart.getName(), - [columnId.repo]: chart => chart.getRepository(), + [columnId.name]: (chart: HelmChart) => chart.getName(), + [columnId.repo]: (chart: HelmChart) => chart.getRepository(), }} searchFilters={[ - chart => chart.getName(), - chart => chart.getVersion(), - chart => chart.getAppVersion(), - chart => chart.getKeywords(), + (chart: HelmChart) => chart.getName(), + (chart: HelmChart) => chart.getVersion(), + (chart: HelmChart) => chart.getAppVersion(), + (chart: HelmChart) => chart.getKeywords(), ]} customizeHeader={() => ( @@ -103,7 +103,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 => [ + renderTableContents={(chart: HelmChart) => [
{ store={releaseStore} dependentStores={[secretsStore]} sortingCallbacks={{ - [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), + [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), }} searchFilters={[ - release => release.getName(), - release => release.getNs(), - release => release.getChart(), - release => release.getStatus(), - release => release.getVersion(), + (release: HelmRelease) => release.getName(), + (release: HelmRelease) => release.getNs(), + (release: HelmRelease) => release.getChart(), + (release: HelmRelease) => release.getStatus(), + (release: HelmRelease) => release.getVersion(), ]} renderHeaderTitle="Releases" customizeHeader={({ filters, ...headerPlaceholders }) => ({ @@ -137,7 +137,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 => [ + renderTableContents={(release: HelmRelease) => [ release.getName(), release.getNs(), release.getChart(), @@ -147,13 +147,13 @@ export class HelmReleases extends Component { { title: release.getStatus(), className: kebabCase(release.getStatus()) }, release.getUpdated(), ]} - renderItemMenu={release => ( + renderItemMenu={(release: HelmRelease) => ( )} - customizeRemoveDialog={selectedItems => ({ + customizeRemoveDialog={(selectedItems: HelmRelease[]) => ({ message: this.renderRemoveDialogMessage(selectedItems) })} detailsItem={this.selectedRelease} diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 7e676c37d4..c2d180d2e2 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -55,7 +55,7 @@ enum sortBy { status = "status" } -interface Props extends RouteComponentProps { } +interface Props extends RouteComponentProps {} @observer export class Catalog extends React.Component { @@ -182,7 +182,7 @@ export class Catalog extends React.Component { )) } - this.addToHotbar(item)}> + this.addToHotbar(item) }> Pin to Hotbar @@ -211,12 +211,12 @@ export class Catalog extends React.Component { store={this.catalogEntityStore} tableId="catalog-items" sortingCallbacks={{ - [sortBy.name]: entity => entity.name, - [sortBy.source]: entity => entity.source, - [sortBy.status]: entity => entity.phase, + [sortBy.name]: (item: CatalogEntityItem) => item.name, + [sortBy.source]: (item: CatalogEntityItem) => item.source, + [sortBy.status]: (item: CatalogEntityItem) => item.phase, }} searchFilters={[ - entity => entity.searchFields, + (entity: CatalogEntityItem) => entity.searchFields, ]} renderTableHeader={[ { title: "", className: styles.iconCell }, @@ -225,14 +225,14 @@ export class Catalog extends React.Component { { title: "Labels", className: styles.labelsCell }, { title: "Status", className: styles.statusCell, sortBy: sortBy.status }, ]} - renderTableContents={entity => [ - this.renderIcon(entity), - entity.name, - entity.source, - entity.labels.map((label) => ), - { title: entity.phase, className: kebabCase(entity.phase) } + renderTableContents={(item: CatalogEntityItem) => [ + this.renderIcon(item), + item.name, + item.source, + item.labels.map((label) => ), + { title: item.phase, className: kebabCase(item.phase) } ]} - onDetails={entity => this.onDetails(entity) } + onDetails={(item: CatalogEntityItem) => this.onDetails(item) } renderItemMenu={this.renderItemMenu} /> ); @@ -248,13 +248,13 @@ export class Catalog extends React.Component { store={this.catalogEntityStore} tableId="catalog-items" sortingCallbacks={{ - [sortBy.name]: entity => entity.name, - [sortBy.kind]: entity => entity.kind, - [sortBy.source]: entity => entity.source, - [sortBy.status]: entity => entity.phase, + [sortBy.name]: (item: CatalogEntityItem) => item.name, + [sortBy.kind]: (item: CatalogEntityItem) => item.kind, + [sortBy.source]: (item: CatalogEntityItem) => item.source, + [sortBy.status]: (item: CatalogEntityItem) => item.phase, }} searchFilters={[ - entity => entity.searchFields, + (entity: CatalogEntityItem) => entity.searchFields, ]} renderTableHeader={[ { title: "", className: styles.iconCell }, @@ -263,16 +263,16 @@ export class Catalog extends React.Component { { title: "Labels", className: styles.labelsCell }, { title: "Status", className: styles.statusCell, sortBy: sortBy.status }, ]} - renderTableContents={entity => [ - this.renderIcon(entity), - entity.name, - entity.kind, - entity.source, - entity.labels.map((label) => ), - { title: entity.phase, className: kebabCase(entity.phase) } + renderTableContents={(item: CatalogEntityItem) => [ + this.renderIcon(item), + item.name, + item.kind, + item.source, + item.labels.map((label) => ), + { title: item.phase, className: kebabCase(item.phase) } ]} detailsItem={this.selectedItem} - onDetails={entity => this.onDetails(entity) } + onDetails={(item: CatalogEntityItem) => this.onDetails(item) } renderItemMenu={this.renderItemMenu} /> ); diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index e418a133f6..54eb0b67a8 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 => 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(), + [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(), }} searchFilters={[ - item => item.getSearchFields() + (item: HorizontalPodAutoscaler) => 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 => [ + renderTableContents={(hpa: HorizontalPodAutoscaler) => [ 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 054b5363f0..6784e6f7d6 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx @@ -28,6 +28,7 @@ import { limitRangeStore } from "./limit-ranges.store"; import type { LimitRangeRouteParams } from "./limit-ranges.route"; import React from "react"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { LimitRange } from "../../api/endpoints/limit-range.api"; enum columnId { name = "name", @@ -48,22 +49,22 @@ export class LimitRanges extends React.Component { className="LimitRanges" store={limitRangeStore} sortingCallbacks={{ - [columnId.name]: item => item.getName(), - [columnId.namespace]: item => item.getNs(), - [columnId.age]: item => item.getTimeDiffFromNow(), + [columnId.name]: (item: LimitRange) => item.getName(), + [columnId.namespace]: (item: LimitRange) => item.getNs(), + [columnId.age]: (item: LimitRange) => item.getTimeDiffFromNow(), }} searchFilters={[ - item => item.getName(), - item => item.getNs(), + (item: LimitRange) => item.getName(), + (item: LimitRange) => 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 => [ + renderTableContents={(limitRange: 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 c2ff98e2d2..b1997fa792 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -25,6 +25,7 @@ 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 type { IConfigMapsRouteParams } from "./config-maps.route"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; @@ -48,14 +49,14 @@ export class ConfigMaps extends React.Component { tableId="configuration_configmaps" className="ConfigMaps" store={configMapsStore} sortingCallbacks={{ - [columnId.name]: item => item.getName(), - [columnId.namespace]: item => item.getNs(), - [columnId.keys]: item => item.getKeys(), - [columnId.age]: item => item.getTimeDiffFromNow(), + [columnId.name]: (item: ConfigMap) => item.getName(), + [columnId.namespace]: (item: ConfigMap) => item.getNs(), + [columnId.keys]: (item: ConfigMap) => item.getKeys(), + [columnId.age]: (item: ConfigMap) => item.getTimeDiffFromNow(), }} searchFilters={[ - item => item.getSearchFields(), - item => item.getKeys() + (item: ConfigMap) => item.getSearchFields(), + (item: ConfigMap) => item.getKeys() ]} renderHeaderTitle="Config Maps" renderTableHeader={[ @@ -65,7 +66,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 => [ + renderTableContents={(configMap: 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 f662c96ab3..abc87a6a4d 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 => 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(), + [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(), }} searchFilters={[ - pdb => pdb.getSearchFields(), + (pdb: PodDisruptionBudget) => 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 => { + renderTableContents={(pdb: PodDisruptionBudget) => { 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 88da84f213..59be708d6f 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -25,6 +25,7 @@ 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 type { IResourceQuotaRouteParams } from "./resource-quotas.route"; @@ -49,13 +50,13 @@ export class ResourceQuotas extends React.Component { tableId="configuration_quotas" className="ResourceQuotas" store={resourceQuotaStore} sortingCallbacks={{ - [columnId.name]: item => item.getName(), - [columnId.namespace]: item => item.getNs(), - [columnId.age]: item => item.getTimeDiffFromNow(), + [columnId.name]: (item: ResourceQuota) => item.getName(), + [columnId.namespace]: (item: ResourceQuota) => item.getNs(), + [columnId.age]: (item: ResourceQuota) => item.getTimeDiffFromNow(), }} searchFilters={[ - item => item.getSearchFields(), - item => item.getName(), + (item: ResourceQuota) => item.getSearchFields(), + (item: ResourceQuota) => item.getName(), ]} renderHeaderTitle="Resource Quotas" renderTableHeader={[ @@ -64,7 +65,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 => [ + renderTableContents={(resourceQuota: ResourceQuota) => [ resourceQuota.getName(), , resourceQuota.getNs(), diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index ec276d4e3c..b87c6a51ed 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -24,6 +24,7 @@ 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 type { ISecretsRouteParams } from "./secrets.route"; import { KubeObjectListLayout } from "../kube-object"; @@ -53,16 +54,16 @@ export class Secrets extends React.Component { tableId="configuration_secrets" className="Secrets" store={secretsStore} sortingCallbacks={{ - [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(), + [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(), }} searchFilters={[ - item => item.getSearchFields(), - item => item.getKeys(), + (item: Secret) => item.getSearchFields(), + (item: Secret) => item.getKeys(), ]} renderHeaderTitle="Secrets" renderTableHeader={[ @@ -74,7 +75,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 => [ + renderTableContents={(secret: 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 60b05a6453..5e44782476 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -32,7 +32,6 @@ 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", @@ -79,11 +78,11 @@ export class CrdList extends React.Component { render() { const { items, selectedGroups } = this; - const sortingCallbacks: TableSortCallbacks = { - [columnId.kind]: crd => crd.getResourceKind(), - [columnId.group]: crd => crd.getGroup(), - [columnId.version]: crd => crd.getVersion(), - [columnId.scope]: crd => crd.getScope(), + 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(), }; return ( @@ -134,7 +133,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 => [ + renderTableContents={(crd: CustomResourceDefinition) => [ {crd.getResourceTitle()} , diff --git a/src/renderer/components/+custom-resources/crd-resource.store.ts b/src/renderer/components/+custom-resources/crd-resource.store.ts index 335a015aa7..8717884785 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 4037494a86..b42703aa33 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -30,7 +30,7 @@ import type { KubeObject } from "../../api/kube-object"; import type { ICRDRouteParams } from "./crd.route"; import { autorun, computed, makeObservable } from "mobx"; import { crdStore } from "./crd.store"; -import type { TableSortCallbacks } from "../table"; +import type { TableSortCallback } from "../table"; import { apiManager } from "../../api/api-manager"; import { parseJsonPath } from "../../utils/jsonPath"; @@ -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: TableSortCallbacks = { - [columnId.name]: item => item.getName(), - [columnId.namespace]: item => item.getNs(), - [columnId.age]: item => item.getTimeDiffFromNow(), + const sortingCallbacks: { [sortBy: string]: TableSortCallback } = { + [columnId.name]: (item: KubeObject) => item.getName(), + [columnId.namespace]: (item: KubeObject) => item.getNs(), + [columnId.age]: (item: KubeObject) => item.getTimeDiffFromNow(), }; extraColumns.forEach(column => { - sortingCallbacks[column.name] = item => jsonPath.value(item, parseJsonPath(column.jsonPath.slice(1))); + sortingCallbacks[column.name] = (item: KubeObject) => 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 => item.getSearchFields(), + (item: KubeObject) => item.getSearchFields(), ]} renderHeaderTitle={crd.getResourceTitle()} renderTableHeader={[ @@ -116,7 +116,7 @@ export class CrdResources extends React.Component { }), { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={crdInstance => [ + renderTableContents={(crdInstance: KubeObject) => [ 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 25415e5ab3..613438bca7 100644 --- a/src/renderer/components/+custom-resources/crd.store.ts +++ b/src/renderer/components/+custom-resources/crd.store.ts @@ -26,18 +26,13 @@ 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 { KubeObject } from "../../api/kube-object"; +import type { 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({ - objectConstructor: KubeObject, - apiBase, - kind, - isNamespaced, - }); + const api = apiManager.getApi(apiBase) || new KubeApi({ 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 a7512ce62b..adf7b2d105 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 } from "../table"; +import type { TableSortCallbacks, TableSortParams, TableProps } from "../table"; import type { IHeaderPlaceholders } 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,13 +69,19 @@ export class Events extends React.Component { orderBy: "asc", }; - 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(), + 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, }; constructor(props: Props) { @@ -150,17 +156,13 @@ export class Events extends React.Component { isSelectable={false} items={visibleItems} virtual={!compact} - tableProps={{ - sortSyncWithUrl: false, - sortByDefault: this.sorting, - onSort: params => this.sorting = params, - }} + tableProps={this.tableConfiguration} sortingCallbacks={this.sortingCallbacks} searchFilters={[ - event => event.getSearchFields(), - event => event.message, - event => event.getSource(), - event => event.involvedObject.name, + (event: KubeEvent) => event.getSearchFields(), + (event: KubeEvent) => event.message, + (event: KubeEvent) => event.getSource(), + (event: KubeEvent) => event.involvedObject.name, ]} renderTableHeader={[ { title: "Type", className: "type", sortBy: columnId.type, id: columnId.type }, @@ -172,7 +174,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 => { + renderTableContents={(event: KubeEvent) => { 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 18876c4aa6..29098c8a49 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -106,7 +106,7 @@ export class NamespaceStore extends KubeObjectStore { return super.getSubscribeApis(); } - protected async loadItems(params: KubeObjectStoreLoadingParams) { + protected async loadItems(params: KubeObjectStoreLoadingParams) { const { allowedNamespaces } = this; let namespaces = (await super.loadItems(params)) || []; diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index 86bd0080a7..60ecc2f3e5 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 { NamespaceStatus } from "../../api/endpoints"; +import { Namespace, 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 => ns.getName(), - [columnId.labels]: ns => ns.getLabels(), - [columnId.age]: ns => ns.getTimeDiffFromNow(), - [columnId.status]: ns => ns.getStatus(), + [columnId.name]: (ns: Namespace) => ns.getName(), + [columnId.labels]: (ns: Namespace) => ns.getLabels(), + [columnId.age]: (ns: Namespace) => ns.getTimeDiffFromNow(), + [columnId.status]: (ns: Namespace) => ns.getStatus(), }} searchFilters={[ - item => item.getSearchFields(), - item => item.getStatus() + (item: Namespace) => item.getSearchFields(), + (item: Namespace) => 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 => [ + renderTableContents={(item: Namespace) => [ item.getName(), , item.getLabels().map(label => ), @@ -79,7 +79,7 @@ export class Namespaces extends React.Component { addTooltip: "Add Namespace", onAdd: () => AddNamespaceDialog.open(), }} - customizeTableRowProps={item => ({ + customizeTableRowProps={(item: Namespace) => ({ disabled: item.getStatus() === NamespaceStatus.TERMINATING, })} /> diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index 0d9a7e125c..7cc74427fa 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -25,6 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; import type { EndpointRouteParams } from "./endpoints.route"; +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"; @@ -48,12 +49,12 @@ export class Endpoints extends React.Component { tableId="network_endpoints" className="Endpoints" store={endpointStore} sortingCallbacks={{ - [columnId.name]: endpoint => endpoint.getName(), - [columnId.namespace]: endpoint => endpoint.getNs(), - [columnId.age]: endpoint => endpoint.getTimeDiffFromNow(), + [columnId.name]: (endpoint: Endpoint) => endpoint.getName(), + [columnId.namespace]: (endpoint: Endpoint) => endpoint.getNs(), + [columnId.age]: (endpoint: Endpoint) => endpoint.getTimeDiffFromNow(), }} searchFilters={[ - endpoint => endpoint.getSearchFields() + (endpoint: Endpoint) => endpoint.getSearchFields() ]} renderHeaderTitle="Endpoints" renderTableHeader={[ @@ -63,7 +64,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 => [ + renderTableContents={(endpoint: Endpoint) => [ endpoint.getName(), , endpoint.getNs(), @@ -71,7 +72,7 @@ export class Endpoints extends React.Component { endpoint.getAge(), ]} tableProps={{ - customRowHeights: (item, lineHeight, paddings) => { + customRowHeights: (item: Endpoint, 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 7b0cc9f608..1ee39d4010 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -25,6 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; import type { IngressRouteParams } from "./ingresses.route"; +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"; @@ -49,13 +50,13 @@ export class Ingresses extends React.Component { tableId="network_ingresses" className="Ingresses" store={ingressStore} sortingCallbacks={{ - [columnId.name]: ingress => ingress.getName(), - [columnId.namespace]: ingress => ingress.getNs(), - [columnId.age]: ingress => ingress.getTimeDiffFromNow(), + [columnId.name]: (ingress: Ingress) => ingress.getName(), + [columnId.namespace]: (ingress: Ingress) => ingress.getNs(), + [columnId.age]: (ingress: Ingress) => ingress.getTimeDiffFromNow(), }} searchFilters={[ - ingress => ingress.getSearchFields(), - ingress => ingress.getPorts(), + (ingress: Ingress) => ingress.getSearchFields(), + (ingress: Ingress) => ingress.getPorts(), ]} renderHeaderTitle="Ingresses" renderTableHeader={[ @@ -66,7 +67,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 => [ + renderTableContents={(ingress: Ingress) => [ ingress.getName(), , ingress.getNs(), @@ -75,7 +76,7 @@ export class Ingresses extends React.Component { ingress.getAge(), ]} tableProps={{ - customRowHeights: (item, lineHeight, paddings) => { + customRowHeights: (item: Ingress, 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 e10430af1e..1010c07175 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -24,6 +24,7 @@ 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 type { INetworkPoliciesRouteParams } from "./network-policies.route"; import { networkPolicyStore } from "./network-policy.store"; @@ -48,12 +49,12 @@ export class NetworkPolicies extends React.Component { tableId="network_policies" className="NetworkPolicies" store={networkPolicyStore} sortingCallbacks={{ - [columnId.name]: item => item.getName(), - [columnId.namespace]: item => item.getNs(), - [columnId.age]: item => item.getTimeDiffFromNow(), + [columnId.name]: (item: NetworkPolicy) => item.getName(), + [columnId.namespace]: (item: NetworkPolicy) => item.getNs(), + [columnId.age]: (item: NetworkPolicy) => item.getTimeDiffFromNow(), }} searchFilters={[ - item => item.getSearchFields(), + (item: NetworkPolicy) => item.getSearchFields(), ]} renderHeaderTitle="Network Policies" renderTableHeader={[ @@ -63,7 +64,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 => [ + renderTableContents={(item: NetworkPolicy) => [ item.getName(), , item.getNs(), diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index 9260d4005d..33f9b73e08 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -25,6 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import type { IServicesRouteParams } from "./services.route"; +import type { Service } from "../../api/endpoints/service.api"; import { KubeObjectListLayout } from "../kube-object"; import { Badge } from "../badge"; import { serviceStore } from "./services.store"; @@ -54,19 +55,19 @@ export class Services extends React.Component { tableId="network_services" className="Services" store={serviceStore} sortingCallbacks={{ - [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(), + [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(), }} searchFilters={[ - service => service.getSearchFields(), - service => service.getSelector().join(" "), - service => service.getPorts().join(" "), + (service: Service) => service.getSearchFields(), + (service: Service) => service.getSelector().join(" "), + (service: Service) => service.getPorts().join(" "), ]} renderHeaderTitle="Services" renderTableHeader={[ @@ -81,7 +82,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 => [ + renderTableContents={(service: Service) => [ service.getName(), , service.getNs(), diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 8ef5f027f7..834ae80a0e 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -171,21 +171,21 @@ export class Nodes extends React.Component { dependentStores={[podsStore]} isSelectable={false} sortingCallbacks={{ - [columnId.name]: node => node.getName(), - [columnId.cpu]: node => nodesStore.getLastMetricValues(node, ["cpuUsage"]), - [columnId.memory]: node => nodesStore.getLastMetricValues(node, ["memoryUsage"]), - [columnId.disk]: node => nodesStore.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(), + [columnId.name]: (node: Node) => node.getName(), + [columnId.cpu]: (node: Node) => nodesStore.getLastMetricValues(node, ["cpuUsage"]), + [columnId.memory]: (node: Node) => nodesStore.getLastMetricValues(node, ["memoryUsage"]), + [columnId.disk]: (node: Node) => nodesStore.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(), }} searchFilters={[ - node => node.getSearchFields(), - node => node.getRoleLabels(), - node => node.getKubeletVersion(), - node => node.getNodeConditionText(), + (node: Node) => node.getSearchFields(), + (node: Node) => node.getRoleLabels(), + (node: Node) => node.getKubeletVersion(), + (node: Node) => node.getNodeConditionText(), ]} renderHeaderTitle="Nodes" renderTableHeader={[ @@ -200,7 +200,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 => { + renderTableContents={(node: 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 c578bf8e34..a74a5e8623 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx @@ -25,6 +25,7 @@ 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 { @@ -44,15 +45,15 @@ export class PodSecurityPolicies extends React.Component { className="PodSecurityPolicies" store={podSecurityPoliciesStore} sortingCallbacks={{ - [columnId.name]: item => item.getName(), - [columnId.volumes]: item => item.getVolumes(), - [columnId.privileged]: item => +item.isPrivileged(), - [columnId.age]: item => item.getTimeDiffFromNow(), + [columnId.name]: (item: PodSecurityPolicy) => item.getName(), + [columnId.volumes]: (item: PodSecurityPolicy) => item.getVolumes(), + [columnId.privileged]: (item: PodSecurityPolicy) => +item.isPrivileged(), + [columnId.age]: (item: PodSecurityPolicy) => item.getTimeDiffFromNow(), }} searchFilters={[ - item => item.getSearchFields(), - item => item.getVolumes(), - item => Object.values(item.getRules()), + (item: PodSecurityPolicy) => item.getSearchFields(), + (item: PodSecurityPolicy) => item.getVolumes(), + (item: PodSecurityPolicy) => Object.values(item.getRules()), ]} renderHeaderTitle="Pod Security Policies" renderTableHeader={[ @@ -62,7 +63,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 => { + renderTableContents={(item: PodSecurityPolicy) => { return [ item.getName(), , diff --git a/src/renderer/components/+storage-classes/storage-classes.tsx b/src/renderer/components/+storage-classes/storage-classes.tsx index dc90e48563..f052e3e8ef 100644 --- a/src/renderer/components/+storage-classes/storage-classes.tsx +++ b/src/renderer/components/+storage-classes/storage-classes.tsx @@ -24,6 +24,7 @@ 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 type { IStorageClassesRouteParams } from "./storage-classes.route"; import { storageClassStore } from "./storage-class.store"; @@ -50,14 +51,14 @@ export class StorageClasses extends React.Component { className="StorageClasses" store={storageClassStore} sortingCallbacks={{ - [columnId.name]: item => item.getName(), - [columnId.age]: item => item.getTimeDiffFromNow(), - [columnId.provisioner]: item => item.provisioner, - [columnId.reclaimPolicy]: item => item.reclaimPolicy, + [columnId.name]: (item: StorageClass) => item.getName(), + [columnId.age]: (item: StorageClass) => item.getTimeDiffFromNow(), + [columnId.provisioner]: (item: StorageClass) => item.provisioner, + [columnId.reclaimPolicy]: (item: StorageClass) => item.reclaimPolicy, }} searchFilters={[ - item => item.getSearchFields(), - item => item.provisioner, + (item: StorageClass) => item.getSearchFields(), + (item: StorageClass) => item.provisioner, ]} renderHeaderTitle="Storage Classes" renderTableHeader={[ @@ -68,7 +69,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 => [ + renderTableContents={(storageClass: 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 8bdf6c3c18..34309b43ec 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -25,6 +25,7 @@ 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 type { IVolumeClaimsRouteParams } from "./volume-claims.route"; @@ -57,17 +58,17 @@ export class PersistentVolumeClaims extends React.Component { store={volumeClaimStore} dependentStores={[podsStore]} sortingCallbacks={{ - [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(), + [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(), }} searchFilters={[ - item => item.getSearchFields(), - item => item.getPods(podsStore.items).map(pod => pod.getName()), + (item: PersistentVolumeClaim) => item.getSearchFields(), + (item: PersistentVolumeClaim) => item.getPods(podsStore.items).map(pod => pod.getName()), ]} renderHeaderTitle="Persistent Volume Claims" renderTableHeader={[ @@ -80,7 +81,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 => { + renderTableContents={(pvc: PersistentVolumeClaim) => { 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 c9c3c898a4..2eb25dbdb3 100644 --- a/src/renderer/components/+storage-volumes/volumes.tsx +++ b/src/renderer/components/+storage-volumes/volumes.tsx @@ -24,6 +24,7 @@ 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 type { IVolumesRouteParams } from "./volumes.route"; import { stopPropagation } from "../../utils"; @@ -53,15 +54,15 @@ export class PersistentVolumes extends React.Component { className="PersistentVolumes" store={volumesStore} sortingCallbacks={{ - [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(), + [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(), }} searchFilters={[ - item => item.getSearchFields(), - item => item.getClaimRefName(), + (item: PersistentVolume) => item.getSearchFields(), + (item: PersistentVolume) => item.getClaimRefName(), ]} renderHeaderTitle="Persistent Volumes" renderTableHeader={[ @@ -73,7 +74,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 => { + renderTableContents={(volume: PersistentVolume) => { const { claimRef, storageClassName } = volume.spec; const storageClassDetailsUrl = getDetailsUrl(storageClassApi.getUrl({ name: storageClassName diff --git a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx index 63ad039d22..273a3c0d51 100644 --- a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx +++ b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx @@ -40,6 +40,7 @@ import { namespaceStore } from "../+namespaces/namespace.store"; import { serviceAccountsStore } from "../+user-management-service-accounts/service-accounts.store"; import { roleBindingsStore } from "./role-bindings.store"; import { showDetails } from "../kube-object"; +import type { KubeObjectStore } from "../../kube-object.store"; interface BindingSelectOption extends SelectOption { value: string; // binding name @@ -101,12 +102,14 @@ export class AddRoleBindingDialog extends React.Component { }; async loadData() { + const stores: KubeObjectStore[] = [ + namespaceStore, + rolesStore, + serviceAccountsStore, + ]; + this.isLoading = true; - await Promise.all([ - namespaceStore.reloadAll(), - rolesStore.reloadAll(), - serviceAccountsStore.reloadAll(), - ]); + await Promise.all(stores.map(store => store.reloadAll())); this.isLoading = false; } diff --git a/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts b/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts index d6149aeb87..25c4285fef 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts @@ -51,7 +51,7 @@ export class RoleBindingsStore extends KubeObjectStore { return clusterRoleBindingApi.get(params); } - protected async loadItems(params: KubeObjectStoreLoadingParams): Promise { + protected async loadItems(params: KubeObjectStoreLoadingParams): Promise { const items = await Promise.all([ super.loadItems({ ...params, api: clusterRoleBindingApi }), super.loadItems({ ...params, api: roleBindingApi }), diff --git a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx index 885de84ade..db86d37cd6 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx @@ -25,6 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import type { IRoleBindingsRouteParams } from "../+user-management/user-management.route"; +import type { RoleBinding } from "../../api/endpoints"; import { roleBindingsStore } from "./role-bindings.store"; import { KubeObjectListLayout } from "../kube-object"; import { AddRoleBindingDialog } from "./add-role-binding-dialog"; @@ -50,14 +51,14 @@ export class RoleBindings extends React.Component { className="RoleBindings" store={roleBindingsStore} sortingCallbacks={{ - [columnId.name]: binding => binding.getName(), - [columnId.namespace]: binding => binding.getNs(), - [columnId.bindings]: binding => binding.getSubjectNames(), - [columnId.age]: binding => binding.getTimeDiffFromNow(), + [columnId.name]: (binding: RoleBinding) => binding.getName(), + [columnId.namespace]: (binding: RoleBinding) => binding.getNs(), + [columnId.bindings]: (binding: RoleBinding) => binding.getSubjectNames(), + [columnId.age]: (binding: RoleBinding) => binding.getTimeDiffFromNow(), }} searchFilters={[ - binding => binding.getSearchFields(), - binding => binding.getSubjectNames(), + (binding: RoleBinding) => binding.getSearchFields(), + (binding: RoleBinding) => binding.getSubjectNames(), ]} renderHeaderTitle="Role Bindings" renderTableHeader={[ @@ -67,7 +68,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 => [ + renderTableContents={(binding: RoleBinding) => [ binding.getName(), , binding.getNs() || "-", diff --git a/src/renderer/components/+user-management-roles/roles.store.ts b/src/renderer/components/+user-management-roles/roles.store.ts index 58b99287b0..a70d3e8abe 100644 --- a/src/renderer/components/+user-management-roles/roles.store.ts +++ b/src/renderer/components/+user-management-roles/roles.store.ts @@ -49,7 +49,7 @@ export class RolesStore extends KubeObjectStore { return clusterRoleApi.get(params); } - protected async loadItems(params: KubeObjectStoreLoadingParams): Promise { + protected async loadItems(params: KubeObjectStoreLoadingParams): Promise { const items = await Promise.all([ super.loadItems({ ...params, api: clusterRoleApi }), super.loadItems({ ...params, api: roleApi }), diff --git a/src/renderer/components/+user-management-roles/roles.tsx b/src/renderer/components/+user-management-roles/roles.tsx index 871eb4c515..ac7385cb2c 100644 --- a/src/renderer/components/+user-management-roles/roles.tsx +++ b/src/renderer/components/+user-management-roles/roles.tsx @@ -26,6 +26,7 @@ import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import type { IRolesRouteParams } from "../+user-management/user-management.route"; import { rolesStore } from "./roles.store"; +import type { Role } from "../../api/endpoints"; import { KubeObjectListLayout } from "../kube-object"; import { AddRoleDialog } from "./add-role-dialog"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; @@ -50,12 +51,12 @@ export class Roles extends React.Component { className="Roles" store={rolesStore} sortingCallbacks={{ - [columnId.name]: role => role.getName(), - [columnId.namespace]: role => role.getNs(), - [columnId.age]: role => role.getTimeDiffFromNow(), + [columnId.name]: (role: Role) => role.getName(), + [columnId.namespace]: (role: Role) => role.getNs(), + [columnId.age]: (role: Role) => role.getTimeDiffFromNow(), }} searchFilters={[ - role => role.getSearchFields(), + (role: Role) => role.getSearchFields(), ]} renderHeaderTitle="Roles" renderTableHeader={[ @@ -64,7 +65,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 => [ + renderTableContents={(role: Role) => [ role.getName(), , role.getNs() || "-", diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx index f8d0cbf951..dff4d1fe58 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx @@ -55,12 +55,12 @@ export class ServiceAccounts extends React.Component { tableId="access_service_accounts" className="ServiceAccounts" store={serviceAccountsStore} sortingCallbacks={{ - [columnId.name]: account => account.getName(), - [columnId.namespace]: account => account.getNs(), - [columnId.age]: account => account.getTimeDiffFromNow(), + [columnId.name]: (account: ServiceAccount) => account.getName(), + [columnId.namespace]: (account: ServiceAccount) => account.getNs(), + [columnId.age]: (account: ServiceAccount) => account.getTimeDiffFromNow(), }} searchFilters={[ - account => account.getSearchFields(), + (account: ServiceAccount) => account.getSearchFields(), ]} renderHeaderTitle="Service Accounts" renderTableHeader={[ @@ -69,7 +69,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 => [ + renderTableContents={(account: ServiceAccount) => [ account.getName(), , account.getNs(), diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index e421e0a82a..04560aa197 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -62,16 +62,16 @@ export class CronJobs extends React.Component { className="CronJobs" store={cronJobStore} dependentStores={[jobStore, eventStore]} sortingCallbacks={{ - [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.getLastScheduleTime(), - [columnId.age]: cronJob => cronJob.getTimeDiffFromNow(), + [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) => cronJob.getLastScheduleTime(), + [columnId.age]: (cronJob: CronJob) => cronJob.getTimeDiffFromNow(), }} searchFilters={[ - cronJob => cronJob.getSearchFields(), - cronJob => cronJob.getSchedule(), + (cronJob: CronJob) => cronJob.getSearchFields(), + (cronJob: CronJob) => cronJob.getSchedule(), ]} renderHeaderTitle="Cron Jobs" renderTableHeader={[ @@ -84,7 +84,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 => [ + renderTableContents={(cronJob: CronJob) => [ cronJob.getName(), , cronJob.getNs(), diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx index 6eb3744149..b256ac1f62 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.getName(), - [columnId.namespace]: daemonSet => daemonSet.getNs(), - [columnId.pods]: daemonSet => this.getPodsLength(daemonSet), - [columnId.age]: daemonSet => daemonSet.getTimeDiffFromNow(), + [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(), }} searchFilters={[ - daemonSet => daemonSet.getSearchFields(), - daemonSet => daemonSet.getLabels(), + (daemonSet: DaemonSet) => daemonSet.getSearchFields(), + (daemonSet: 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 => [ + renderTableContents={(daemonSet: 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 ba9eaeca8e..74ddb08fcb 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -82,15 +82,15 @@ export class Deployments extends React.Component { className="Deployments" store={deploymentStore} dependentStores={[replicaSetStore, podsStore, nodesStore, eventStore]} sortingCallbacks={{ - [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(), + [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(), }} searchFilters={[ - deployment => deployment.getSearchFields(), - deployment => deployment.getConditionsText(), + (deployment: Deployment) => deployment.getSearchFields(), + (deployment: Deployment) => deployment.getConditionsText(), ]} renderHeaderTitle="Deployments" renderTableHeader={[ @@ -102,7 +102,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 => [ + renderTableContents={(deployment: Deployment) => [ deployment.getName(), , deployment.getNs(), @@ -111,7 +111,9 @@ export class Deployments extends React.Component { deployment.getAge(), this.renderConditions(deployment), ]} - renderItemMenu={item => } + renderItemMenu={(item: Deployment) => { + return ; + }} /> ); } diff --git a/src/renderer/components/+workloads-jobs/jobs.tsx b/src/renderer/components/+workloads-jobs/jobs.tsx index 9ecb6d08ab..bcc9b85efe 100644 --- a/src/renderer/components/+workloads-jobs/jobs.tsx +++ b/src/renderer/components/+workloads-jobs/jobs.tsx @@ -27,6 +27,7 @@ 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 type { IJobsRouteParams } from "../+workloads"; import kebabCase from "lodash/kebabCase"; @@ -53,13 +54,13 @@ export class Jobs extends React.Component { className="Jobs" store={jobStore} dependentStores={[podsStore, eventStore]} sortingCallbacks={{ - [columnId.name]: job => job.getName(), - [columnId.namespace]: job => job.getNs(), - [columnId.conditions]: job => job.getCondition() != null ? job.getCondition().type : "", - [columnId.age]: job => job.getTimeDiffFromNow(), + [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(), }} searchFilters={[ - job => job.getSearchFields(), + (job: Job) => job.getSearchFields(), ]} renderHeaderTitle="Jobs" renderTableHeader={[ @@ -70,7 +71,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 => { + renderTableContents={(job: 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 89194c2d96..21ae379b69 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -46,7 +46,7 @@ const resources: KubeResource[] = [ export class OverviewStatuses extends React.Component { @boundMethod renderWorkload(resource: KubeResource): React.ReactElement { - const store = workloadStores.get(resource); + const store = workloadStores[resource]; 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 306ebf9a25..5ca65cc2b3 100644 --- a/src/renderer/components/+workloads-pods/pod-tolerations.tsx +++ b/src/renderer/components/+workloads-pods/pod-tolerations.tsx @@ -37,6 +37,13 @@ enum sortBy { Seconds = "seconds", } +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 } = toleration; @@ -59,17 +66,10 @@ export function PodTolerations({ tolerations }: Props) { toleration.key, - [sortBy.Operator]: toleration => toleration.operator, - [sortBy.Effect]: toleration => toleration.effect, - [sortBy.Seconds]: toleration => toleration.tolerationSeconds, - }} + sortable={sortingCallbacks} sortSyncWithUrl={false} className="PodTolerations" - renderRow={getTableRow} > Key @@ -77,6 +77,9 @@ 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 e9ccdbe181..be5cbf8852 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.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(), + [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(), }} searchFilters={[ - pod => pod.getSearchFields(), - pod => pod.getStatusMessage(), - pod => pod.status.podIP, - pod => pod.getNodeName(), + (pod: Pod) => pod.getSearchFields(), + (pod: Pod) => pod.getStatusMessage(), + (pod: Pod) => pod.status.podIP, + (pod: 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 => [ + renderTableContents={(pod: Pod) => [ , , pod.getNs(), diff --git a/src/renderer/components/+workloads-replicasets/replicasets.tsx b/src/renderer/components/+workloads-replicasets/replicasets.tsx index 2556e56c3e..ffc75ead0e 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.tsx +++ b/src/renderer/components/+workloads-replicasets/replicasets.tsx @@ -56,15 +56,15 @@ export class ReplicaSets extends React.Component { tableId="workload_replicasets" className="ReplicaSets" store={replicaSetStore} sortingCallbacks={{ - [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(), + [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(), }} searchFilters={[ - replicaSet => replicaSet.getSearchFields(), + (replicaSet: ReplicaSet) => replicaSet.getSearchFields(), ]} renderHeaderTitle="Replica Sets" renderTableHeader={[ @@ -76,7 +76,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 => [ + renderTableContents={(replicaSet: ReplicaSet) => [ replicaSet.getName(), , replicaSet.getNs(), diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx index 27632e0d54..59b208cccf 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx @@ -65,13 +65,13 @@ export class StatefulSets extends React.Component { className="StatefulSets" store={statefulSetStore} dependentStores={[podsStore, nodesStore, eventStore]} sortingCallbacks={{ - [columnId.name]: statefulSet => statefulSet.getName(), - [columnId.namespace]: statefulSet => statefulSet.getNs(), - [columnId.age]: statefulSet => statefulSet.getTimeDiffFromNow(), - [columnId.replicas]: statefulSet => statefulSet.getReplicas(), + [columnId.name]: (statefulSet: StatefulSet) => statefulSet.getName(), + [columnId.namespace]: (statefulSet: StatefulSet) => statefulSet.getNs(), + [columnId.age]: (statefulSet: StatefulSet) => statefulSet.getTimeDiffFromNow(), + [columnId.replicas]: (statefulSet: StatefulSet) => statefulSet.getReplicas(), }} searchFilters={[ - statefulSet => statefulSet.getSearchFields(), + (statefulSet: StatefulSet) => statefulSet.getSearchFields(), ]} renderHeaderTitle="Stateful Sets" renderTableHeader={[ @@ -82,7 +82,7 @@ export class StatefulSets extends React.Component { { className: "warning", showWithColumn: columnId.replicas }, { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, ]} - renderTableContents={statefulSet => [ + renderTableContents={(statefulSet: StatefulSet) => [ statefulSet.getName(), statefulSet.getNs(), this.renderPods(statefulSet), @@ -90,7 +90,9 @@ export class StatefulSets extends React.Component { , statefulSet.getAge(), ]} - renderItemMenu={item => } + renderItemMenu={(item: StatefulSet) => { + return ; + }} /> ); } diff --git a/src/renderer/components/+workloads/workloads.stores.ts b/src/renderer/components/+workloads/workloads.stores.ts index e53ea7cb03..a06c17200d 100644 --- a/src/renderer/components/+workloads/workloads.stores.ts +++ b/src/renderer/components/+workloads/workloads.stores.ts @@ -28,14 +28,13 @@ 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 = new Map>([ - ["pods", podsStore], - ["deployments", deploymentStore], - ["daemonsets", daemonSetStore], - ["statefulsets", statefulSetStore], - ["replicasets", replicaSetStore], - ["jobs", jobStore], - ["cronjobs", cronJobStore], -]); +export const workloadStores: Partial> = { + "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 0630176927..9b10491901 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 a9333ae50f..647cbcaec9 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, TableSortCallbacks } from "../table"; +import { Table, TableCell, TableCellProps, TableHead, TableProps, TableRow, TableRowProps, TableSortCallback } 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"; @@ -46,10 +46,8 @@ import { NamespaceSelectFilter } from "../+namespaces/namespace-select-filter"; // todo: refactor, split to small re-usable components -export type SearchFilter = (item: I) => string | number | (string | number)[]; -export type SearchFilters = Record>; -export type ItemsFilter = (items: I[]) => I[]; -export type ItemsFilters = Record>; +export type SearchFilter = (item: T) => string | number | (string | number)[]; +export type ItemsFilter = (items: T[]) => T[]; export interface IHeaderPlaceholders { title: ReactNode; @@ -58,22 +56,22 @@ export interface IHeaderPlaceholders { info: ReactNode; } -export interface ItemListLayoutProps { +export interface ItemListLayoutProps { tableId?: string; className: IClassName; - items?: I[]; - store: ItemStore; - dependentStores?: ItemStore[]; + items?: T[]; + 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?: (placeholders: IHeaderPlaceholders, content: ReactNode) => Partial | ReactNode; // items list configuration @@ -82,28 +80,26 @@ export interface ItemListLayoutProps { isSearchable?: boolean; // apply search-filter & add search-input isConfigurable?: boolean; copyClassNameFromHeadCells?: boolean; - sortingCallbacks?: TableSortCallbacks; - tableProps?: Partial>; // low-level table configuration + sortingCallbacks?: { [sortBy: string]: TableSortCallback }; + tableProps?: Partial; // low-level table configuration renderTableHeader: TableCellProps[] | null; - renderTableContents: (item: I) => (ReactNode | TableCellProps)[]; - renderItemMenu?: (item: I, store: ItemStore) => ReactNode; - customizeTableRowProps?: (item: I) => Partial; + renderTableContents: (item: T) => (ReactNode | TableCellProps)[]; + renderItemMenu?: (item: T, store: ItemStore) => ReactNode; + customizeTableRowProps?: (item: T) => Partial; addRemoveButtons?: Partial; virtual?: boolean; // item details view hasDetailsView?: boolean; - detailsItem?: I; - onDetails?: (item: I) => void; + detailsItem?: T; + onDetails?: (item: T) => void; // other - customizeRemoveDialog?: (selectedItems: I[]) => Partial; - renderFooter?: (parent: ItemListLayout) => React.ReactNode; - - filterCallbacks?: ItemsFilters; + customizeRemoveDialog?: (selectedItems: T[]) => Partial; + renderFooter?: (parent: ItemListLayout) => React.ReactNode; } -const defaultProps: Partial> = { +const defaultProps: Partial = { showHeader: true, isSearchable: true, isSelectable: true, @@ -119,14 +115,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); } @@ -162,7 +158,7 @@ export class ItemListLayout extends React.Component store.loadAll(namespaceStore.contextNamespaces)); } - private filterCallbacks: ItemsFilters = { + private filterCallbacks: { [type: string]: ItemsFilter } = { [FilterType.SEARCH]: items => { const { searchFilters, isSearchable } = this.props; const search = pageFilters.getValues(FilterType.SEARCH)[0] || ""; @@ -203,20 +199,20 @@ export class ItemListLayout extends React.Component[], items: I[]): I[] { + applyFilters(filters: ItemsFilter[], items: T[]): T[] { if (!filters || !filters.length) return items; return filters.reduce((items, filter) => filter(items), items); } @computed get items() { - const { filters, filterCallbacks, props } = this; + const { filters, filterCallbacks } = this; const filterGroups = groupBy(filters, ({ type }) => type); - const filterItems: ItemsFilter[] = []; + const filterItems: ItemsFilter[] = []; Object.entries(filterGroups).forEach(([type, filtersGroup]) => { - const filterCallback = filterCallbacks[type] ?? props.filterCallbacks?.[type]; + const filterCallback = 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 44c8b42545..217c7c25c8 100644 --- a/src/renderer/components/kube-object/kube-object-details.tsx +++ b/src/renderer/components/kube-object/kube-object-details.tsx @@ -33,7 +33,6 @@ import { crdStore } from "../+custom-resources/crd.store"; import { CrdResourceDetails } from "../+custom-resources"; import { KubeObjectMenu } from "./kube-object-menu"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; -import { CustomResourceDefinition } from "../../api/endpoints"; /** * Used to store `object.selfLink` to show more info about resource in the details panel. @@ -100,7 +99,15 @@ export class KubeObjectDetails extends React.Component { } @computed get object() { - return apiManager.getStore(this.path)?.getByPath(this.path); + const store = apiManager.getStore(this.path); + + if (store) { + return store.getByPath(this.path); + } + } + + @computed get isCrdInstance() { + return !!crdStore.getByObject(this.object); } @disposeOnUnmount @@ -130,7 +137,7 @@ export class KubeObjectDetails extends React.Component { }); render() { - const { object, isLoading, loadingError } = this; + const { object, isLoading, loadingError, isCrdInstance } = this; const isOpen = !!(object || isLoading || loadingError); let title = ""; let details: React.ReactNode[]; @@ -143,7 +150,7 @@ export class KubeObjectDetails extends React.Component { return ; }); - if (object instanceof CustomResourceDefinition && details.length === 0) { + if (isCrdInstance && details.length === 0) { details.push(); } } diff --git a/src/renderer/components/kube-object/kube-object-list-layout.tsx b/src/renderer/components/kube-object/kube-object-list-layout.tsx index cfd79adaed..52c886f6a2 100644 --- a/src/renderer/components/kube-object/kube-object-list-layout.tsx +++ b/src/renderer/components/kube-object/kube-object-list-layout.tsx @@ -30,22 +30,21 @@ import { KubeObjectMenu } from "./kube-object-menu"; import { kubeSelectedUrlParam, showDetails } from "./kube-object-details"; import { kubeWatchApi } from "../../api/kube-watch-api"; import { clusterContext } from "../context"; -import { FilterType, pageFilters } from "../item-object-list/page-filters.store"; -export interface KubeObjectListLayoutProps extends ItemListLayoutProps { - store: KubeObjectStore; - dependentStores?: KubeObjectStore[]; +export interface KubeObjectListLayoutProps 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); } @@ -77,18 +76,7 @@ export class KubeObjectListLayout extends React.Component< items={items} preloadStores={false} // loading handled in kubeWatchApi.subscribeStores() detailsItem={this.selectedItem} - renderItemMenu={(item: K) => } // safe because we are dealing with KubeObjects here - filterCallbacks={{ - [FilterType.NAMESPACE]: items => { - const filterValues = pageFilters.getValues(FilterType.NAMESPACE); - - if (filterValues.length > 0) { - return items.filter(item => filterValues.includes(item.getNs())); - } - - return items; - }, - }} + renderItemMenu={(item: KubeObject) => } // safe because we are dealing with KubeObjects here /> ); } diff --git a/src/renderer/components/table/table.tsx b/src/renderer/components/table/table.tsx index bb5e63f570..c1cc7f0cd6 100644 --- a/src/renderer/components/table/table.tsx +++ b/src/renderer/components/table/table.tsx @@ -30,18 +30,19 @@ 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: Item) => string | number | (string | number)[]; -export type TableSortCallbacks = Record>; +export type TableSortCallback = (data: D) => string | number | (string | number)[]; +export type TableSortCallbacks = { [columnId: string]: TableSortCallback }; -export interface TableProps extends React.DOMAttributes { +export interface TableProps extends React.DOMAttributes { tableId?: string; - items?: Item[]; // Raw items data + items?: ItemObject[]; // Raw items data className?: string; autoSize?: boolean; // Setup auto-sizing for all columns (flex: 1 0) selectable?: boolean; // Highlight rows on hover @@ -51,7 +52,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 @@ -60,9 +61,8 @@ export interface TableProps extends React.DOMAttributes { virtual?: boolean; // Use virtual list component to render only visible rows rowPadding?: string; rowLineHeight?: string; - customRowHeights?: (item: Item, lineHeight: number, paddings: number) => number; + customRowHeights?: (item: object, 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,20 +171,9 @@ export class Table extends React.Component> { }); } - 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(); + const { sortable, noItems, children, virtual, customRowHeights, rowLineHeight, rowPadding, items, getTableRow, selectedItemId, className } = this.props; + const content = React.Children.toArray(children) as (TableRowElem | TableHeadElem)[]; 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/item.store.ts b/src/renderer/item.store.ts index c8aa656d81..83733dea41 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: Item) => item.getName(); + protected defaultSorting = (item: T) => 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(): Item[] { + @computed get selectedItems(): T[] { return this.items.filter(item => this.selectedItemsIds.get(item.getId())); } - public getItems(): Item[] { + public getItems(): T[] { return Array.from(this.items); } @@ -56,8 +56,8 @@ export abstract class ItemStore { return this.items.length; } - getByName(name: string, ...args: any[]): Item; - getByName(name: string): Item { + getByName(name: string, ...args: any[]): T; + getByName(name: string): T { 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: Item[] = this.items, sorting: ((item: Item) => any)[] = [this.defaultSorting], order?: "asc" | "desc"): Item[] { + protected sortItems(items: T[] = this.items, sorting: ((item: T) => any)[] = [this.defaultSorting], order?: "asc" | "desc"): T[] { 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: Item, request: () => Promise) { + protected async updateItem(item: T, 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: Item, request: () => Promise) { + protected async removeItem(item: T, request: () => Promise) { await request(); this.items.remove(item); this.selectedItemsIds.delete(item.getId()); } - isSelected(item: Item) { + isSelected(item: T) { return !!this.selectedItemsIds.get(item.getId()); } @action - select(item: Item) { + select(item: T) { this.selectedItemsIds.set(item.getId(), true); } @action - unselect(item: Item) { + unselect(item: T) { this.selectedItemsIds.delete(item.getId()); } @action - toggleSelection(item: Item) { + toggleSelection(item: T) { if (this.isSelected(item)) { this.unselect(item); } else { @@ -181,7 +181,7 @@ export abstract class ItemStore { } @action - toggleSelectionAll(visibleItems: Item[] = this.items) { + toggleSelectionAll(visibleItems: T[] = this.items) { const allSelected = visibleItems.every(this.isSelected); if (allSelected) { @@ -191,7 +191,7 @@ export abstract class ItemStore { } } - isSelectedAll(visibleItems: Item[] = this.items) { + isSelectedAll(visibleItems: T[] = this.items) { if (!visibleItems.length) return false; return visibleItems.every(this.isSelected); @@ -218,7 +218,7 @@ export abstract class ItemStore { return noop; } - *[Symbol.iterator]() { + * [Symbol.iterator]() { yield* this.items; } } diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index ca3fff747d..f1b9cfba96 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 ItemStore } } - 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,8 +279,8 @@ export abstract class KubeObjectStore extends ItemStore } async update(item: T, data: Partial): Promise { - const newItem = await item.update(data); - + const newItem = await item.update(data); + ensureObjectSelfLink(this.api, newItem); const index = this.items.findIndex(item => item.getId() === newItem.getId()); @@ -309,8 +309,7 @@ export abstract class KubeObjectStore extends ItemStore }); } - getSubscribeApis(): KubeApi[] { - // TODO remove this function, each Store should only be a single API + getSubscribeApis(): KubeApi[] { return [this.api]; } @@ -362,7 +361,7 @@ export abstract class KubeObjectStore extends ItemStore 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) { @@ -410,7 +409,7 @@ export abstract class KubeObjectStore extends ItemStore switch (type) { case "ADDED": case "MODIFIED": - const newItem = new api.objectConstructor(object) as T; + const newItem = new api.objectConstructor(object); if (!item) { items.push(newItem);