From 8edeeb64e757bd86851c05b34aacc828f6defc2d Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 17 Sep 2020 10:11:30 -0400 Subject: [PATCH] refactor overview statuses to be more DRY Signed-off-by: Sebastian Malton --- src/common/rbac.ts | 26 ++++++ .../+workloads-cronjobs/cronjob.store.ts | 4 +- .../+workloads-daemonsets/daemonsets.store.ts | 11 ++- .../deployments.store.ts | 11 ++- .../components/+workloads-jobs/job.store.ts | 4 +- .../+workloads-overview/overview-statuses.tsx | 88 ++++++++----------- .../components/+workloads-pods/pods.store.ts | 4 +- .../statefulset.store.ts | 11 ++- src/renderer/components/+workloads/index.ts | 2 +- .../components/+workloads/workloads.route.ts | 10 +++ .../components/+workloads/workloads.stores.ts | 17 ++++ src/renderer/kube-object.store.ts | 8 ++ 12 files changed, 118 insertions(+), 78 deletions(-) create mode 100644 src/renderer/components/+workloads/workloads.stores.ts diff --git a/src/common/rbac.ts b/src/common/rbac.ts index 363a94f3e2..c949f6bb58 100644 --- a/src/common/rbac.ts +++ b/src/common/rbac.ts @@ -6,6 +6,32 @@ export type KubeResource = "pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" | "endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" +export const ResourceNames: Record = { + "namespaces": "Namespaces", + "nodes": "Nodes", + "events": "Events", + "resourcequotas": "Resource Quotas", + "services": "Services", + "secrets": "Secrets", + "configmaps": "Config Maps", + "ingresses": "Ingresses", + "networkpolicies": "Network Policies", + "persistentvolumes": "Persistent Volumes", + "storageclasses": "Storage Classes", + "pods": "Pods", + "daemonsets": "Daemon Sets", + "deployments": "Deployments", + "statefulsets": "Stateful Sets", + "replicasets": "Replica Sets", + "jobs": "Jobs", + "cronjobs": "Cron Jobs", + "endpoints": "Endpoints", + "customresourcedefinitions": "Custom Resource Definitions", + "horizontalpodautoscalers": "Horizontal Pod Autoscalers", + "podsecuritypolicies": "Pod Security Policies", + "poddisruptionbudgets": "Pod Disruption Budgets", +} + export interface KubeApiResource { resource: KubeResource; // valid resource name group?: string; // api-group diff --git a/src/renderer/components/+workloads-cronjobs/cronjob.store.ts b/src/renderer/components/+workloads-cronjobs/cronjob.store.ts index e8fa3719ae..9b6584cf2e 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob.store.ts +++ b/src/renderer/components/+workloads-cronjobs/cronjob.store.ts @@ -1,11 +1,11 @@ -import { KubeObjectStore } from "../../kube-object.store"; +import { StatusKubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { CronJob, cronJobApi } from "../../api/endpoints/cron-job.api"; import { jobStore } from "../+workloads-jobs/job.store"; import { apiManager } from "../../api/api-manager"; @autobind() -export class CronJobStore extends KubeObjectStore { +export class CronJobStore extends StatusKubeObjectStore { api = cronJobApi getStatuses(cronJobs?: CronJob[]) { diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.store.ts b/src/renderer/components/+workloads-daemonsets/daemonsets.store.ts index 3e9acdd036..fc9ad4cd8f 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.store.ts +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.store.ts @@ -1,21 +1,20 @@ import { observable } from "mobx"; -import { KubeObjectStore } from "../../kube-object.store"; +import { StatusKubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { DaemonSet, daemonSetApi, IPodMetrics, Pod, podsApi, PodStatus } from "../../api/endpoints"; import { podsStore } from "../+workloads-pods/pods.store"; import { apiManager } from "../../api/api-manager"; @autobind() -export class DaemonSetStore extends KubeObjectStore { +export class DaemonSetStore extends StatusKubeObjectStore { api = daemonSetApi @observable metrics: IPodMetrics = null; - loadMetrics(daemonSet: DaemonSet) { + async loadMetrics(daemonSet: DaemonSet) { const pods = this.getChildPods(daemonSet); - return podsApi.getMetrics(pods, daemonSet.getNs(), "").then(metrics => - this.metrics = metrics - ); + const metrics = await podsApi.getMetrics(pods, daemonSet.getNs(), ""); + return this.metrics = metrics; } getChildPods(daemonSet: DaemonSet): Pod[] { diff --git a/src/renderer/components/+workloads-deployments/deployments.store.ts b/src/renderer/components/+workloads-deployments/deployments.store.ts index 59acd6c100..4c3e60d4d6 100644 --- a/src/renderer/components/+workloads-deployments/deployments.store.ts +++ b/src/renderer/components/+workloads-deployments/deployments.store.ts @@ -1,12 +1,12 @@ import { observable } from "mobx"; import { Deployment, deploymentApi, IPodMetrics, podsApi, PodStatus } from "../../api/endpoints"; -import { KubeObjectStore } from "../../kube-object.store"; +import { StatusKubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { podsStore } from "../+workloads-pods/pods.store"; import { apiManager } from "../../api/api-manager"; @autobind() -export class DeploymentStore extends KubeObjectStore { +export class DeploymentStore extends StatusKubeObjectStore { api = deploymentApi @observable metrics: IPodMetrics = null; @@ -16,11 +16,10 @@ export class DeploymentStore extends KubeObjectStore { ], "desc"); } - loadMetrics(deployment: Deployment) { + async loadMetrics(deployment: Deployment) { const pods = this.getChildPods(deployment); - return podsApi.getMetrics(pods, deployment.getNs(), "").then(metrics => - this.metrics = metrics - ); + const metrics = await podsApi.getMetrics(pods, deployment.getNs(), ""); + return this.metrics = metrics; } getStatuses(deployments?: Deployment[]) { diff --git a/src/renderer/components/+workloads-jobs/job.store.ts b/src/renderer/components/+workloads-jobs/job.store.ts index 592347062c..42684faf48 100644 --- a/src/renderer/components/+workloads-jobs/job.store.ts +++ b/src/renderer/components/+workloads-jobs/job.store.ts @@ -1,4 +1,4 @@ -import { KubeObjectStore } from "../../kube-object.store"; +import { StatusKubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { Job, jobApi } from "../../api/endpoints/job.api"; import { CronJob, Pod, PodStatus } from "../../api/endpoints"; @@ -6,7 +6,7 @@ import { podsStore } from "../+workloads-pods/pods.store"; import { apiManager } from "../../api/api-manager"; @autobind() -export class JobStore extends KubeObjectStore { +export class JobStore extends StatusKubeObjectStore { api = jobApi getChildPods(job: Job): Pod[] { diff --git a/src/renderer/components/+workloads-overview/overview-statuses.tsx b/src/renderer/components/+workloads-overview/overview-statuses.tsx index be770cd39a..8177fbb3c0 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -5,72 +5,54 @@ import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; import { OverviewWorkloadStatus } from "./overview-workload-status"; import { Link } from "react-router-dom"; -import { cronJobsURL, daemonSetsURL, deploymentsURL, jobsURL, podsURL, statefulSetsURL } from "../+workloads"; -import { podsStore } from "../+workloads-pods/pods.store"; -import { deploymentStore } from "../+workloads-deployments/deployments.store"; -import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store"; -import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store"; -import { jobStore } from "../+workloads-jobs/job.store"; -import { cronJobStore } from "../+workloads-cronjobs/cronjob.store"; +import { resourceURL, resourceStores } from "../+workloads"; import { namespaceStore } from "../+namespaces/namespace.store"; import { PageFiltersList } from "../item-object-list/page-filters-list"; import { NamespaceSelectFilter } from "../+namespaces/namespace-select"; -import { isAllowedResource } from "../../../common/rbac"; +import { isAllowedResource, KubeResource, ResourceNames } from "../../../common/rbac"; +import { autobind } from "../../utils"; +import { _i18n } from "../../i18n"; + +const resources: KubeResource[] = [ + "pods", + "deployments", + "statefulsets", + "daemonsets", + "jobs", + "cronjobs", +] @observer export class OverviewStatuses extends React.Component { + @autobind() + renderWorkload(resource: KubeResource): React.ReactElement | null { + const store = resourceStores[resource]; + const items = store.getAllByNs([...namespaceStore.contextNs]) + const name = _i18n._(ResourceNames[resource]) + return ( +
+
+ {name} ({items.length}) +
+ +
+ ) + } + render() { - const { contextNs } = namespaceStore; - const pods = isAllowedResource("pods") ? podsStore.getAllByNs(contextNs) : []; - const deployments = isAllowedResource("deployments") ? deploymentStore.getAllByNs(contextNs) : []; - const statefulSets = isAllowedResource("statefulsets") ? statefulSetStore.getAllByNs(contextNs) : []; - const daemonSets = isAllowedResource("daemonsets") ? daemonSetStore.getAllByNs(contextNs) : []; - const jobs = isAllowedResource("jobs") ? jobStore.getAllByNs(contextNs) : []; - const cronJobs = isAllowedResource("cronjobs") ? cronJobStore.getAllByNs(contextNs) : []; + const workloads = resources + .filter(isAllowedResource) + .map(this.renderWorkload); + return (
Overview
- +
- +
- {isAllowedResource("pods") && -
-
Pods ({pods.length})
- -
- } - {isAllowedResource("deployments") && -
-
Deployments ({deployments.length})
- -
- } - {isAllowedResource("statefulsets") && -
-
StatefulSets ({statefulSets.length})
- -
- } - {isAllowedResource("daemonsets") && -
-
DaemonSets ({daemonSets.length})
- -
- } - {isAllowedResource("jobs") && -
-
Jobs ({jobs.length})
- -
- } - {isAllowedResource("cronjobs") && -
-
CronJobs ({cronJobs.length})
- -
- } + {workloads}
) diff --git a/src/renderer/components/+workloads-pods/pods.store.ts b/src/renderer/components/+workloads-pods/pods.store.ts index fe95ba4e48..704a908d46 100644 --- a/src/renderer/components/+workloads-pods/pods.store.ts +++ b/src/renderer/components/+workloads-pods/pods.store.ts @@ -1,13 +1,13 @@ import countBy from "lodash/countBy"; import { action, observable } from "mobx"; -import { KubeObjectStore } from "../../kube-object.store"; +import { StatusKubeObjectStore } from "../../kube-object.store"; import { autobind, cpuUnitsToNumber, unitsToBytes } from "../../utils"; import { IPodMetrics, Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints"; import { WorkloadKubeObject } from "../../api/workload-kube-object"; import { apiManager } from "../../api/api-manager"; @autobind() -export class PodsStore extends KubeObjectStore { +export class PodsStore extends StatusKubeObjectStore { api = podsApi; @observable metrics: IPodMetrics = null; diff --git a/src/renderer/components/+workloads-statefulsets/statefulset.store.ts b/src/renderer/components/+workloads-statefulsets/statefulset.store.ts index 5119ce6e00..dc1a3d05fc 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset.store.ts +++ b/src/renderer/components/+workloads-statefulsets/statefulset.store.ts @@ -1,20 +1,19 @@ import { observable } from "mobx"; import { autobind } from "../../utils"; -import { KubeObjectStore } from "../../kube-object.store"; +import { StatusKubeObjectStore } from "../../kube-object.store"; import { IPodMetrics, podsApi, PodStatus, StatefulSet, statefulSetApi } from "../../api/endpoints"; import { podsStore } from "../+workloads-pods/pods.store"; import { apiManager } from "../../api/api-manager"; @autobind() -export class StatefulSetStore extends KubeObjectStore { +export class StatefulSetStore extends StatusKubeObjectStore { api = statefulSetApi @observable metrics: IPodMetrics = null; - loadMetrics(statefulSet: StatefulSet) { + async loadMetrics(statefulSet: StatefulSet) { const pods = this.getChildPods(statefulSet); - return podsApi.getMetrics(pods, statefulSet.getNs(), "").then(metrics => - this.metrics = metrics - ); + const metrics = await podsApi.getMetrics(pods, statefulSet.getNs(), ""); + return this.metrics = metrics; } getChildPods(statefulSet: StatefulSet) { diff --git a/src/renderer/components/+workloads/index.ts b/src/renderer/components/+workloads/index.ts index 300747c6af..1f2ae11149 100644 --- a/src/renderer/components/+workloads/index.ts +++ b/src/renderer/components/+workloads/index.ts @@ -1,3 +1,3 @@ export * from "./workloads.route" export * from "./workloads" - +export * from "./workloads.stores" diff --git a/src/renderer/components/+workloads/workloads.route.ts b/src/renderer/components/+workloads/workloads.route.ts index 94a7afd6ba..2983ed571b 100644 --- a/src/renderer/components/+workloads/workloads.route.ts +++ b/src/renderer/components/+workloads/workloads.route.ts @@ -1,6 +1,7 @@ import { RouteProps } from "react-router" import { Workloads } from "./workloads"; import { buildURL, IURLParams } from "../../navigation"; +import { KubeResource } from "../../../common/rbac"; export const workloadsRoute: RouteProps = { get path() { @@ -62,3 +63,12 @@ export const daemonSetsURL = buildURL(daemonSetsRoute.pa export const statefulSetsURL = buildURL(statefulSetsRoute.path) export const jobsURL = buildURL(jobsRoute.path) export const cronJobsURL = buildURL(cronJobsRoute.path) + +export const resourceURL: Partial>> = { + "pods": podsURL, + "deployments": deploymentsURL, + "daemonsets": daemonSetsURL, + "statefulsets": statefulSetsURL, + "jobs": jobsURL, + "cronjobs": cronJobsURL, +} diff --git a/src/renderer/components/+workloads/workloads.stores.ts b/src/renderer/components/+workloads/workloads.stores.ts new file mode 100644 index 0000000000..8cdf29e78c --- /dev/null +++ b/src/renderer/components/+workloads/workloads.stores.ts @@ -0,0 +1,17 @@ +import { StatusKubeObjectStore } from "../../kube-object.store"; +import { podsStore } from "../+workloads-pods/pods.store"; +import { deploymentStore } from "../+workloads-deployments/deployments.store"; +import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store"; +import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store"; +import { jobStore } from "../+workloads-jobs/job.store"; +import { cronJobStore } from "../+workloads-cronjobs/cronjob.store"; +import { KubeResource } from "../../../common/rbac"; + +export const resourceStores: Partial> = { + "pods": podsStore, + "deployments": deploymentStore, + "daemonsets": daemonSetStore, + "statefulsets": statefulSetStore, + "jobs": jobStore, + "cronjobs": cronJobStore, +} diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index 0f647ced6d..fdee80784a 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -198,3 +198,11 @@ export abstract class KubeObjectStore extends ItemSt this.items.replace(this.sortItems(items)); } } + +export interface Statuses { + [key: string]: number; +} + +export abstract class StatusKubeObjectStore extends KubeObjectStore { + abstract getStatuses(items: T[]): Statuses; +}