From a62e1fc4e57da43ddbffeddc2ac05b8677289ff3 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 14 Dec 2020 21:33:51 -0500 Subject: [PATCH] cleanup KubeObjectListLayout Signed-off-by: Sebastian Malton --- src/renderer/api/api-manager.ts | 25 ++++---- src/renderer/api/endpoints/secret.api.ts | 8 +-- src/renderer/api/kube-api.ts | 2 +- src/renderer/api/kube-watch-api.ts | 3 +- .../components/+apps-releases/releases.tsx | 64 ++++++++----------- .../components/+config-secrets/secrets.tsx | 22 +++---- .../+custom-resources/crd-resources.tsx | 10 +-- .../+workloads-pods/pod-container-env.tsx | 12 ++-- .../item-object-list/item-list-layout.tsx | 12 ++-- .../kube-object/kube-object-list-layout.tsx | 22 +++---- src/renderer/components/table/table.tsx | 10 +-- src/renderer/kube-object.store.ts | 2 +- 12 files changed, 89 insertions(+), 103 deletions(-) diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index 68d4773540..12ad8910c2 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -3,18 +3,19 @@ import type { KubeObjectStore } from "../kube-object.store"; import { action, observable } from "mobx"; import { autobind } from "../utils"; import { KubeApi } from "./kube-api"; +import { KubeObject } from "./kube-object"; @autobind() export class ApiManager { private apis = observable.map(); - private stores = observable.map(); + private stores = observable.map>(); - getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) { + getApi(pathOrCallback: string | ((api: KubeApi) => boolean) = () => true) { if (typeof pathOrCallback === "string") { return this.apis.get(pathOrCallback) || this.apis.get(KubeApi.parseApi(pathOrCallback).apiBase); } - return Array.from(this.apis.values()).find(pathOrCallback ?? (() => true)); + return Array.from(this.apis.values()).find(pathOrCallback); } registerApi(apiBase: string, api: KubeApi) { @@ -29,24 +30,26 @@ export class ApiManager { return api; } - unregisterApi(api: string | KubeApi) { - if (typeof api === "string") this.apis.delete(api); - else { - const apis = Array.from(this.apis.entries()); - const entry = apis.find(entry => entry[1] === api); + unregisterApi(api: string | KubeApi): void { + if (typeof api === "string") { + return void this.apis.delete(api); + } - if (entry) this.unregisterApi(entry[0]); + for (const [apiPath, kubeApi] of this.apis) { + if (kubeApi === api) { + return void this.apis.delete(apiPath); + } } } @action - registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { + registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { apis.forEach(api => { this.stores.set(api, store); }); } - getStore(api: string | KubeApi): KubeObjectStore { + getStore(api: string | KubeApi): KubeObjectStore { return this.stores.get(this.resolveApi(api)); } } diff --git a/src/renderer/api/endpoints/secret.api.ts b/src/renderer/api/endpoints/secret.api.ts index 16262570df..08f8902628 100644 --- a/src/renderer/api/endpoints/secret.api.ts +++ b/src/renderer/api/endpoints/secret.api.ts @@ -1,5 +1,4 @@ import { KubeObject } from "../kube-object"; -import { KubeJsonApiData } from "../kube-json-api"; import { autobind } from "../../utils"; import { KubeApi } from "../kube-api"; @@ -29,12 +28,7 @@ export class Secret extends KubeObject { data: { [prop: string]: string; token?: string; - }; - - constructor(data: KubeJsonApiData) { - super(data); - this.data = this.data || {}; - } + } = {}; getKeys(): string[] { return Object.keys(this.data); diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index e7934675c6..a0d60a7598 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -79,7 +79,7 @@ export function forCluster(cluster: IKubeApiCluster, kubeC }); } -export class KubeApi { +export class KubeApi { static parseApi = parseKubeApi; static watchAll(...apis: KubeApi[]) { diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 58665a11a1..41ed6eea38 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -9,6 +9,7 @@ import { KubeApi } from "./kube-api"; import { apiManager } from "./api-manager"; import { apiPrefix, isDevelopment } from "../../common/vars"; import { getHostedCluster } from "../../common/cluster-store"; +import { KubeObject } from "./kube-object"; export interface IKubeWatchEvent { type: "ADDED" | "MODIFIED" | "DELETED"; @@ -156,7 +157,7 @@ export class KubeWatchApi { } } - addListener(store: KubeObjectStore, callback: (evt: IKubeWatchEvent) => void) { + addListener(store: KubeObjectStore, callback: (evt: IKubeWatchEvent) => void) { const listener = (evt: IKubeWatchEvent) => { const { selfLink, namespace, resourceVersion } = evt.object.metadata; const api = apiManager.getApi(selfLink); diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index bcc18965ac..b2c33dbf58 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -86,19 +86,19 @@ export class HelmReleases extends Component { store={releaseStore} dependentStores={[secretsStore]} sortingCallbacks={{ - [sortBy.name]: (release: HelmRelease) => release.getName(), - [sortBy.namespace]: (release: HelmRelease) => release.getNs(), - [sortBy.revision]: (release: HelmRelease) => release.getRevision(), - [sortBy.chart]: (release: HelmRelease) => release.getChart(), - [sortBy.status]: (release: HelmRelease) => release.getStatus(), - [sortBy.updated]: (release: HelmRelease) => release.getUpdated(false, false), + [sortBy.name]: release => release.getName(), + [sortBy.namespace]: release => release.getNs(), + [sortBy.revision]: release => release.getRevision(), + [sortBy.chart]: release => release.getChart(), + [sortBy.status]: release => release.getStatus(), + [sortBy.updated]: release => release.getUpdated(false, false), }} searchFilters={[ - (release: HelmRelease) => release.getName(), - (release: HelmRelease) => release.getNs(), - (release: HelmRelease) => release.getChart(), - (release: HelmRelease) => release.getStatus(), - (release: HelmRelease) => release.getVersion(), + release => release.getName(), + release => release.getNs(), + release => release.getChart(), + release => release.getStatus(), + release => release.getVersion(), ]} renderHeaderTitle={Releases} renderTableHeader={[ @@ -111,31 +111,23 @@ export class HelmReleases extends Component { { title: Status, className: "status", sortBy: sortBy.status }, { title: Updated, className: "updated", sortBy: sortBy.updated }, ]} - renderTableContents={(release: HelmRelease) => { - const version = release.getVersion(); - - return [ - release.getName(), - release.getNs(), - release.getChart(), - release.getRevision(), - <> - {version} - , - release.appVersion, - { title: release.getStatus(), className: kebabCase(release.getStatus()) }, - release.getUpdated(), - ]; - }} - renderItemMenu={(release: HelmRelease) => { - return ( - - ); - }} - customizeRemoveDialog={(selectedItems: HelmRelease[]) => ({ + renderTableContents={release => [ + release.getName(), + release.getNs(), + release.getChart(), + release.getRevision(), + release.getVersion(), + release.appVersion, + { title: release.getStatus(), className: kebabCase(release.getStatus()) }, + release.getUpdated(), + ]} + renderItemMenu={release => ( + + )} + customizeRemoveDialog={selectedItems => ({ message: this.renderRemoveDialogMessage(selectedItems) })} detailsItem={this.selectedRelease} diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index 2e1c2c0197..81e2d6e144 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -4,7 +4,6 @@ import React from "react"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { RouteComponentProps } from "react-router"; -import { Secret } from "../../api/endpoints"; import { AddSecretDialog } from "./add-secret-dialog"; import { ISecretsRouteParams } from "./secrets.route"; import { KubeObjectListLayout } from "../kube-object"; @@ -30,18 +29,19 @@ export class Secrets extends React.Component { return ( <> item.getName(), - [sortBy.namespace]: (item: Secret) => item.getNs(), - [sortBy.labels]: (item: Secret) => item.getLabels(), - [sortBy.keys]: (item: Secret) => item.getKeys(), - [sortBy.type]: (item: Secret) => item.type, - [sortBy.age]: (item: Secret) => item.metadata.creationTimestamp, + [sortBy.name]: secret => secret.getName(), + [sortBy.namespace]: secret => secret.getNs(), + [sortBy.labels]: secret => secret.getLabels(), + [sortBy.keys]: secret => secret.getKeys(), + [sortBy.type]: secret => secret.type, + [sortBy.age]: secret => secret.metadata.creationTimestamp, }} searchFilters={[ - (item: Secret) => item.getSearchFields(), - (item: Secret) => item.getKeys(), + secret => secret.getSearchFields(), + secret => secret.getKeys(), ]} renderHeaderTitle={Secrets} renderTableHeader={[ @@ -53,7 +53,7 @@ export class Secrets extends React.Component { { title: Type, className: "type", sortBy: sortBy.type }, { title: Age, className: "age", sortBy: sortBy.age }, ]} - renderTableContents={(secret: Secret) => [ + renderTableContents={secret => [ secret.getName(), , secret.getNs(), diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index a4a52ef867..7b31b2f3b8 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -54,14 +54,14 @@ export class CrdResources extends React.Component { if (!crd) return null; const isNamespaced = crd.isNamespaced(); const extraColumns = crd.getPrinterColumns(false); // Cols with priority bigger than 0 are shown in details - const sortingCallbacks: { [sortBy: string]: TableSortCallback } = { - [sortBy.name]: (item: KubeObject) => item.getName(), - [sortBy.namespace]: (item: KubeObject) => item.getNs(), - [sortBy.age]: (item: KubeObject) => item.metadata.creationTimestamp, + const sortingCallbacks: { [sortBy: string]: TableSortCallback } = { + [sortBy.name]: item => item.getName(), + [sortBy.namespace]: item => item.getNs(), + [sortBy.age]: item => item.metadata.creationTimestamp, }; extraColumns.forEach(column => { - sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, column.jsonPath.slice(1)); + sortingCallbacks[column.name] = item => jsonPath.value(item, column.jsonPath.slice(1)); }); return ( diff --git a/src/renderer/components/+workloads-pods/pod-container-env.tsx b/src/renderer/components/+workloads-pods/pod-container-env.tsx index daff533310..2fe0cb440e 100644 --- a/src/renderer/components/+workloads-pods/pod-container-env.tsx +++ b/src/renderer/components/+workloads-pods/pod-container-env.tsx @@ -23,17 +23,13 @@ export const ContainerEnvironment = observer((props: Props) => { useEffect( () => autorun(() => { - env && env.forEach(variable => { - const { valueFrom } = variable; - - if (valueFrom && valueFrom.configMapKeyRef) { + env?.forEach(({ valueFrom }) => { + if (valueFrom?.configMapKeyRef) { configMapsStore.load({ name: valueFrom.configMapKeyRef.name, namespace }); } }); - envFrom && envFrom.forEach(item => { - const { configMapRef } = item; - - if (configMapRef && configMapRef.name) { + envFrom?.forEach(({ configMapRef }) => { + if (configMapRef?.name) { configMapsStore.load({ name: configMapRef.name, namespace }); } }); 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 86478faa03..963667cf98 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -44,7 +44,7 @@ export interface ItemListLayoutProps { // 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 @@ -52,8 +52,8 @@ export interface ItemListLayoutProps { isSelectable?: boolean; // show checkbox in rows for selecting items isSearchable?: boolean; // apply search-filter & add search-input copyClassNameFromHeadCells?: boolean; - sortingCallbacks?: { [sortBy: string]: TableSortCallback }; - tableProps?: Partial; // low-level table configuration + sortingCallbacks?: { [sortBy: string]: TableSortCallback }; + tableProps?: Partial>; // low-level table configuration renderTableHeader: TableCellProps[] | null; renderTableContents: (item: T) => (ReactNode | TableCellProps)[]; renderItemMenu?: (item: T, store: ItemStore) => ReactNode; @@ -68,7 +68,7 @@ export interface ItemListLayoutProps { // other customizeRemoveDialog?: (selectedItems: T[]) => Partial; - renderFooter?: (parent: ItemListLayout) => React.ReactNode; + renderFooter?: (parent: ItemListLayout) => React.ReactNode; } const defaultProps: Partial = { @@ -88,7 +88,7 @@ interface ItemListLayoutUserSettings { } @observer -export class ItemListLayout extends React.Component { +export class ItemListLayout extends React.Component> { static defaultProps = defaultProps as object; @observable isUnmounting = false; @@ -98,7 +98,7 @@ export class ItemListLayout extends React.Component { showAppliedFilters: false, }; - constructor(props: ItemListLayoutProps) { + constructor(props: ItemListLayoutProps) { super(props); // keep ui user settings in local storage 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 e68194f0f4..0dd95328d8 100644 --- a/src/renderer/components/kube-object/kube-object-list-layout.tsx +++ b/src/renderer/components/kube-object/kube-object-list-layout.tsx @@ -7,24 +7,24 @@ import { getSelectedDetails, showDetails } from "../../navigation"; import { ItemListLayout, ItemListLayoutProps } from "../item-object-list/item-list-layout"; import { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectMenu } from "./kube-object-menu"; +import { ItemObject } from "../../item.store"; -export interface KubeObjectListLayoutProps extends ItemListLayoutProps { - store: KubeObjectStore; +export interface KubeObjectListLayoutProps extends ItemListLayoutProps { + store: KubeObjectStore; +} + +function showItemDetails(item: KubeObject) { + return showDetails(item.selfLink); } @observer -export class KubeObjectListLayout extends React.Component { +export class KubeObjectListLayout extends React.Component> { @computed get selectedItem() { return this.props.store.getByPath(getSelectedDetails()); } - onDetails = (item: KubeObject) => { - if (this.props.onDetails) { - this.props.onDetails(item); - } - else { - showDetails(item.selfLink); - } + static defaultProps = { + onDetails: showItemDetails }; render() { @@ -35,7 +35,7 @@ export class KubeObjectListLayout extends React.Component { return ; }} diff --git a/src/renderer/components/table/table.tsx b/src/renderer/components/table/table.tsx index a055ab432b..9720a61f8c 100644 --- a/src/renderer/components/table/table.tsx +++ b/src/renderer/components/table/table.tsx @@ -17,9 +17,9 @@ import { ItemObject } from "../../item.store"; export type TableSortBy = string; export type TableOrderBy = "asc" | "desc" | string; export type TableSortParams = { sortBy: TableSortBy; orderBy: TableOrderBy }; -export type TableSortCallback = (data: D) => string | number | (string | number)[]; +export type TableSortCallback = (data: D) => string | number | (string | number)[]; -export interface TableProps extends React.DOMAttributes { +export interface TableProps extends React.DOMAttributes { items?: ItemObject[]; // Raw items data className?: string; autoSize?: boolean; // Setup auto-sizing for all columns (flex: 1 0) @@ -29,7 +29,7 @@ export interface TableProps extends React.DOMAttributes { sortable?: { // Define sortable callbacks for every column in // @sortItem argument in the callback is an object, provided in - [sortBy: string]: TableSortCallback; + [sortBy: string]: TableSortCallback; }; sortSyncWithUrl?: boolean; // sorting state is managed globally from url params sortByDefault?: Partial; // default sorting params @@ -44,8 +44,8 @@ export interface TableProps extends React.DOMAttributes { } @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", diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index e23adf3566..e2013f2679 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -9,7 +9,7 @@ import { KubeJsonApiData } from "./api/kube-json-api"; import { getHostedCluster } from "../common/cluster-store"; @autobind() -export abstract class KubeObjectStore extends ItemStore { +export abstract class KubeObjectStore extends ItemStore { abstract api: KubeApi; public readonly limit?: number; public readonly bufferSize: number = 50000;