1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

refactor overview statuses to be more DRY

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2020-09-17 10:11:30 -04:00
parent 0fedba5b66
commit 8edeeb64e7
12 changed files with 118 additions and 78 deletions

View File

@ -6,6 +6,32 @@ export type KubeResource =
"pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" | "pods" | "daemonsets" | "deployments" | "statefulsets" | "replicasets" | "jobs" | "cronjobs" |
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets" "endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets"
export const ResourceNames: Record<KubeResource, string> = {
"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 { export interface KubeApiResource {
resource: KubeResource; // valid resource name resource: KubeResource; // valid resource name
group?: string; // api-group group?: string; // api-group

View File

@ -1,11 +1,11 @@
import { KubeObjectStore } from "../../kube-object.store"; import { StatusKubeObjectStore } from "../../kube-object.store";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
import { CronJob, cronJobApi } from "../../api/endpoints/cron-job.api"; import { CronJob, cronJobApi } from "../../api/endpoints/cron-job.api";
import { jobStore } from "../+workloads-jobs/job.store"; import { jobStore } from "../+workloads-jobs/job.store";
import { apiManager } from "../../api/api-manager"; import { apiManager } from "../../api/api-manager";
@autobind() @autobind()
export class CronJobStore extends KubeObjectStore<CronJob> { export class CronJobStore extends StatusKubeObjectStore<CronJob> {
api = cronJobApi api = cronJobApi
getStatuses(cronJobs?: CronJob[]) { getStatuses(cronJobs?: CronJob[]) {

View File

@ -1,21 +1,20 @@
import { observable } from "mobx"; import { observable } from "mobx";
import { KubeObjectStore } from "../../kube-object.store"; import { StatusKubeObjectStore } from "../../kube-object.store";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
import { DaemonSet, daemonSetApi, IPodMetrics, Pod, podsApi, PodStatus } from "../../api/endpoints"; import { DaemonSet, daemonSetApi, IPodMetrics, Pod, podsApi, PodStatus } from "../../api/endpoints";
import { podsStore } from "../+workloads-pods/pods.store"; import { podsStore } from "../+workloads-pods/pods.store";
import { apiManager } from "../../api/api-manager"; import { apiManager } from "../../api/api-manager";
@autobind() @autobind()
export class DaemonSetStore extends KubeObjectStore<DaemonSet> { export class DaemonSetStore extends StatusKubeObjectStore<DaemonSet> {
api = daemonSetApi api = daemonSetApi
@observable metrics: IPodMetrics = null; @observable metrics: IPodMetrics = null;
loadMetrics(daemonSet: DaemonSet) { async loadMetrics(daemonSet: DaemonSet) {
const pods = this.getChildPods(daemonSet); const pods = this.getChildPods(daemonSet);
return podsApi.getMetrics(pods, daemonSet.getNs(), "").then(metrics => const metrics = await podsApi.getMetrics(pods, daemonSet.getNs(), "");
this.metrics = metrics return this.metrics = metrics;
);
} }
getChildPods(daemonSet: DaemonSet): Pod[] { getChildPods(daemonSet: DaemonSet): Pod[] {

View File

@ -1,12 +1,12 @@
import { observable } from "mobx"; import { observable } from "mobx";
import { Deployment, deploymentApi, IPodMetrics, podsApi, PodStatus } from "../../api/endpoints"; 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 { autobind } from "../../utils";
import { podsStore } from "../+workloads-pods/pods.store"; import { podsStore } from "../+workloads-pods/pods.store";
import { apiManager } from "../../api/api-manager"; import { apiManager } from "../../api/api-manager";
@autobind() @autobind()
export class DeploymentStore extends KubeObjectStore<Deployment> { export class DeploymentStore extends StatusKubeObjectStore<Deployment> {
api = deploymentApi api = deploymentApi
@observable metrics: IPodMetrics = null; @observable metrics: IPodMetrics = null;
@ -16,11 +16,10 @@ export class DeploymentStore extends KubeObjectStore<Deployment> {
], "desc"); ], "desc");
} }
loadMetrics(deployment: Deployment) { async loadMetrics(deployment: Deployment) {
const pods = this.getChildPods(deployment); const pods = this.getChildPods(deployment);
return podsApi.getMetrics(pods, deployment.getNs(), "").then(metrics => const metrics = await podsApi.getMetrics(pods, deployment.getNs(), "");
this.metrics = metrics return this.metrics = metrics;
);
} }
getStatuses(deployments?: Deployment[]) { getStatuses(deployments?: Deployment[]) {

View File

@ -1,4 +1,4 @@
import { KubeObjectStore } from "../../kube-object.store"; import { StatusKubeObjectStore } from "../../kube-object.store";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
import { Job, jobApi } from "../../api/endpoints/job.api"; import { Job, jobApi } from "../../api/endpoints/job.api";
import { CronJob, Pod, PodStatus } from "../../api/endpoints"; import { CronJob, Pod, PodStatus } from "../../api/endpoints";
@ -6,7 +6,7 @@ import { podsStore } from "../+workloads-pods/pods.store";
import { apiManager } from "../../api/api-manager"; import { apiManager } from "../../api/api-manager";
@autobind() @autobind()
export class JobStore extends KubeObjectStore<Job> { export class JobStore extends StatusKubeObjectStore<Job> {
api = jobApi api = jobApi
getChildPods(job: Job): Pod[] { getChildPods(job: Job): Pod[] {

View File

@ -5,72 +5,54 @@ import { observer } from "mobx-react";
import { Trans } from "@lingui/macro"; import { Trans } from "@lingui/macro";
import { OverviewWorkloadStatus } from "./overview-workload-status"; import { OverviewWorkloadStatus } from "./overview-workload-status";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { cronJobsURL, daemonSetsURL, deploymentsURL, jobsURL, podsURL, statefulSetsURL } from "../+workloads"; import { resourceURL, resourceStores } 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 { namespaceStore } from "../+namespaces/namespace.store"; import { namespaceStore } from "../+namespaces/namespace.store";
import { PageFiltersList } from "../item-object-list/page-filters-list"; import { PageFiltersList } from "../item-object-list/page-filters-list";
import { NamespaceSelectFilter } from "../+namespaces/namespace-select"; 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 @observer
export class OverviewStatuses extends React.Component { 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 (
<div className="workload" key={resource}>
<div className="title">
<Link to={resourceURL[resource]()}>{name} ({items.length})</Link>
</div>
<OverviewWorkloadStatus status={store.getStatuses(items)} />
</div>
)
}
render() { render() {
const { contextNs } = namespaceStore; const workloads = resources
const pods = isAllowedResource("pods") ? podsStore.getAllByNs(contextNs) : []; .filter(isAllowedResource)
const deployments = isAllowedResource("deployments") ? deploymentStore.getAllByNs(contextNs) : []; .map(this.renderWorkload);
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) : [];
return ( return (
<div className="OverviewStatuses"> <div className="OverviewStatuses">
<div className="header flex gaps align-center"> <div className="header flex gaps align-center">
<h5 className="box grow"><Trans>Overview</Trans></h5> <h5 className="box grow"><Trans>Overview</Trans></h5>
<NamespaceSelectFilter/> <NamespaceSelectFilter />
</div> </div>
<PageFiltersList/> <PageFiltersList />
<div className="workloads"> <div className="workloads">
{isAllowedResource("pods") && {workloads}
<div className="workload">
<div className="title"><Link to={podsURL()}><Trans>Pods</Trans> ({pods.length})</Link></div>
<OverviewWorkloadStatus status={podsStore.getStatuses(pods)}/>
</div>
}
{isAllowedResource("deployments") &&
<div className="workload">
<div className="title"><Link to={deploymentsURL()}><Trans>Deployments</Trans> ({deployments.length})</Link></div>
<OverviewWorkloadStatus status={deploymentStore.getStatuses(deployments)}/>
</div>
}
{isAllowedResource("statefulsets") &&
<div className="workload">
<div className="title"><Link to={statefulSetsURL()}><Trans>StatefulSets</Trans> ({statefulSets.length})</Link></div>
<OverviewWorkloadStatus status={statefulSetStore.getStatuses(statefulSets)}/>
</div>
}
{isAllowedResource("daemonsets") &&
<div className="workload">
<div className="title"><Link to={daemonSetsURL()}><Trans>DaemonSets</Trans> ({daemonSets.length})</Link></div>
<OverviewWorkloadStatus status={daemonSetStore.getStatuses(daemonSets)}/>
</div>
}
{isAllowedResource("jobs") &&
<div className="workload">
<div className="title"><Link to={jobsURL()}><Trans>Jobs</Trans> ({jobs.length})</Link></div>
<OverviewWorkloadStatus status={jobStore.getStatuses(jobs)}/>
</div>
}
{isAllowedResource("cronjobs") &&
<div className="workload">
<div className="title"><Link to={cronJobsURL()}><Trans>CronJobs</Trans> ({cronJobs.length})</Link></div>
<OverviewWorkloadStatus status={cronJobStore.getStatuses(cronJobs)}/>
</div>
}
</div> </div>
</div> </div>
) )

View File

@ -1,13 +1,13 @@
import countBy from "lodash/countBy"; import countBy from "lodash/countBy";
import { action, observable } from "mobx"; import { action, observable } from "mobx";
import { KubeObjectStore } from "../../kube-object.store"; import { StatusKubeObjectStore } from "../../kube-object.store";
import { autobind, cpuUnitsToNumber, unitsToBytes } from "../../utils"; import { autobind, cpuUnitsToNumber, unitsToBytes } from "../../utils";
import { IPodMetrics, Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints"; import { IPodMetrics, Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints";
import { WorkloadKubeObject } from "../../api/workload-kube-object"; import { WorkloadKubeObject } from "../../api/workload-kube-object";
import { apiManager } from "../../api/api-manager"; import { apiManager } from "../../api/api-manager";
@autobind() @autobind()
export class PodsStore extends KubeObjectStore<Pod> { export class PodsStore extends StatusKubeObjectStore<Pod> {
api = podsApi; api = podsApi;
@observable metrics: IPodMetrics = null; @observable metrics: IPodMetrics = null;

View File

@ -1,20 +1,19 @@
import { observable } from "mobx"; import { observable } from "mobx";
import { autobind } from "../../utils"; 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 { IPodMetrics, podsApi, PodStatus, StatefulSet, statefulSetApi } from "../../api/endpoints";
import { podsStore } from "../+workloads-pods/pods.store"; import { podsStore } from "../+workloads-pods/pods.store";
import { apiManager } from "../../api/api-manager"; import { apiManager } from "../../api/api-manager";
@autobind() @autobind()
export class StatefulSetStore extends KubeObjectStore<StatefulSet> { export class StatefulSetStore extends StatusKubeObjectStore<StatefulSet> {
api = statefulSetApi api = statefulSetApi
@observable metrics: IPodMetrics = null; @observable metrics: IPodMetrics = null;
loadMetrics(statefulSet: StatefulSet) { async loadMetrics(statefulSet: StatefulSet) {
const pods = this.getChildPods(statefulSet); const pods = this.getChildPods(statefulSet);
return podsApi.getMetrics(pods, statefulSet.getNs(), "").then(metrics => const metrics = await podsApi.getMetrics(pods, statefulSet.getNs(), "");
this.metrics = metrics return this.metrics = metrics;
);
} }
getChildPods(statefulSet: StatefulSet) { getChildPods(statefulSet: StatefulSet) {

View File

@ -1,3 +1,3 @@
export * from "./workloads.route" export * from "./workloads.route"
export * from "./workloads" export * from "./workloads"
export * from "./workloads.stores"

View File

@ -1,6 +1,7 @@
import { RouteProps } from "react-router" import { RouteProps } from "react-router"
import { Workloads } from "./workloads"; import { Workloads } from "./workloads";
import { buildURL, IURLParams } from "../../navigation"; import { buildURL, IURLParams } from "../../navigation";
import { KubeResource } from "../../../common/rbac";
export const workloadsRoute: RouteProps = { export const workloadsRoute: RouteProps = {
get path() { get path() {
@ -62,3 +63,12 @@ export const daemonSetsURL = buildURL<IDaemonSetsRouteParams>(daemonSetsRoute.pa
export const statefulSetsURL = buildURL<IStatefulSetsRouteParams>(statefulSetsRoute.path) export const statefulSetsURL = buildURL<IStatefulSetsRouteParams>(statefulSetsRoute.path)
export const jobsURL = buildURL<IJobsRouteParams>(jobsRoute.path) export const jobsURL = buildURL<IJobsRouteParams>(jobsRoute.path)
export const cronJobsURL = buildURL<ICronJobsRouteParams>(cronJobsRoute.path) export const cronJobsURL = buildURL<ICronJobsRouteParams>(cronJobsRoute.path)
export const resourceURL: Partial<Record<KubeResource, ReturnType<typeof buildURL>>> = {
"pods": podsURL,
"deployments": deploymentsURL,
"daemonsets": daemonSetsURL,
"statefulsets": statefulSetsURL,
"jobs": jobsURL,
"cronjobs": cronJobsURL,
}

View File

@ -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<Record<KubeResource, StatusKubeObjectStore>> = {
"pods": podsStore,
"deployments": deploymentStore,
"daemonsets": daemonSetStore,
"statefulsets": statefulSetStore,
"jobs": jobStore,
"cronjobs": cronJobStore,
}

View File

@ -198,3 +198,11 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
this.items.replace(this.sortItems(items)); this.items.replace(this.sortItems(items));
} }
} }
export interface Statuses {
[key: string]: number;
}
export abstract class StatusKubeObjectStore<T extends KubeObject = any> extends KubeObjectStore<T> {
abstract getStatuses(items: T[]): Statuses;
}