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" |
"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 {
resource: KubeResource; // valid resource name
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 { 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<CronJob> {
export class CronJobStore extends StatusKubeObjectStore<CronJob> {
api = cronJobApi
getStatuses(cronJobs?: CronJob[]) {

View File

@ -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<DaemonSet> {
export class DaemonSetStore extends StatusKubeObjectStore<DaemonSet> {
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[] {

View File

@ -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<Deployment> {
export class DeploymentStore extends StatusKubeObjectStore<Deployment> {
api = deploymentApi
@observable metrics: IPodMetrics = null;
@ -16,11 +16,10 @@ export class DeploymentStore extends KubeObjectStore<Deployment> {
], "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[]) {

View File

@ -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<Job> {
export class JobStore extends StatusKubeObjectStore<Job> {
api = jobApi
getChildPods(job: Job): Pod[] {

View File

@ -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 (
<div className="workload" key={resource}>
<div className="title">
<Link to={resourceURL[resource]()}>{name} ({items.length})</Link>
</div>
<OverviewWorkloadStatus status={store.getStatuses(items)} />
</div>
)
}
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 (
<div className="OverviewStatuses">
<div className="header flex gaps align-center">
<h5 className="box grow"><Trans>Overview</Trans></h5>
<NamespaceSelectFilter/>
<NamespaceSelectFilter />
</div>
<PageFiltersList/>
<PageFiltersList />
<div className="workloads">
{isAllowedResource("pods") &&
<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>
}
{workloads}
</div>
</div>
)

View File

@ -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<Pod> {
export class PodsStore extends StatusKubeObjectStore<Pod> {
api = podsApi;
@observable metrics: IPodMetrics = null;

View File

@ -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<StatefulSet> {
export class StatefulSetStore extends StatusKubeObjectStore<StatefulSet> {
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) {

View File

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

View File

@ -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<IDaemonSetsRouteParams>(daemonSetsRoute.pa
export const statefulSetsURL = buildURL<IStatefulSetsRouteParams>(statefulSetsRoute.path)
export const jobsURL = buildURL<IJobsRouteParams>(jobsRoute.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));
}
}
export interface Statuses {
[key: string]: number;
}
export abstract class StatusKubeObjectStore<T extends KubeObject = any> extends KubeObjectStore<T> {
abstract getStatuses(items: T[]): Statuses;
}