diff --git a/src/common/k8s-api/endpoints/metrics.api/request-pod-metrics-for-jobs.injectable.ts b/src/common/k8s-api/endpoints/metrics.api/request-pod-metrics-for-jobs.injectable.ts index a812fae59c..d52f028cf0 100644 --- a/src/common/k8s-api/endpoints/metrics.api/request-pod-metrics-for-jobs.injectable.ts +++ b/src/common/k8s-api/endpoints/metrics.api/request-pod-metrics-for-jobs.injectable.ts @@ -24,7 +24,7 @@ const requestPodMetricsForJobsInjectable = getInjectable({ instantiate: (di): RequestPodMetricsForJobs => { const requestMetrics = di.inject(requestMetricsInjectable); - return (jobs, namespace, selector) => { + return (jobs, namespace, selector = "") => { const podSelector = jobs.map(job => `${job.getName()}-[[:alnum:]]{5}`).join("|"); const opts = { category: "pods", pods: podSelector, namespace, selector }; diff --git a/src/renderer/components/+workloads-jobs/job-details.tsx b/src/renderer/components/+workloads-jobs/job-details.tsx index fbfb272eab..388032cac7 100644 --- a/src/renderer/components/+workloads-jobs/job-details.tsx +++ b/src/renderer/components/+workloads-jobs/job-details.tsx @@ -17,22 +17,14 @@ import type { JobStore } from "./store"; import type { KubeObjectDetailsProps } from "../kube-object-details"; import { Job } from "../../../common/k8s-api/endpoints"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; -import { KubeObjectMeta } from "../kube-object-meta"; -import { makeObservable, observable, reaction } from "mobx"; -import { podMetricTabs, PodCharts } from "../+workloads-pods/pod-charts"; -import { ClusterMetricsResourceType } from "../../../common/cluster-types"; -import { ResourceMetrics } from "../resource-metrics"; -import logger from "../../../common/logger"; +import type { Logger } from "../../../common/logger"; import { withInjectables } from "@ogre-tools/injectable-react"; import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api"; import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable"; import type { PodStore } from "../+workloads-pods/store"; import podStoreInjectable from "../+workloads-pods/store.injectable"; import jobStoreInjectable from "./store.injectable"; -import type { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable"; -import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable"; -import type { JobPodMetricData, RequestPodMetricsForJobs } from "../../../common/k8s-api/endpoints/metrics.api/request-pod-metrics-for-jobs.injectable"; -import requestPodMetricsForJobsInjectable from "../../../common/k8s-api/endpoints/metrics.api/request-pod-metrics-for-jobs.injectable"; +import loggerInjectable from "../../../common/logger.injectable"; export interface JobDetailsProps extends KubeObjectDetailsProps { } @@ -41,38 +33,21 @@ interface Dependencies { subscribeStores: SubscribeStores; podStore: PodStore; jobStore: JobStore; - getActiveClusterEntity: GetActiveClusterEntity; - requestPodMetricsForJobs: RequestPodMetricsForJobs; + logger: Logger; } @observer class NonInjectedJobDetails extends React.Component { - @observable metrics: JobPodMetricData | null = null; - - constructor(props: JobDetailsProps & Dependencies) { - super(props); - makeObservable(this); - } - componentDidMount() { disposeOnUnmount(this, [ - reaction(() => this.props.object, () => { - this.metrics = null; - }), this.props.subscribeStores([ this.props.podStore, ]), ]); } - loadMetrics = async () => { - const { object: job, requestPodMetricsForJobs } = this.props; - - this.metrics = await requestPodMetricsForJobs([job], job.getNs(), ""); - }; - render() { - const { object: job, jobStore, getActiveClusterEntity } = this.props; + const { object: job, jobStore, logger } = this.props; if (!job) { return null; @@ -89,21 +64,9 @@ class NonInjectedJobDetails extends React.Component - {!isMetricHidden && ( - - - - )} - { Object.keys(selectors).map(label => ) @@ -161,8 +124,7 @@ export const JobDetails = withInjectables(NonInje subscribeStores: di.inject(subscribeStoresInjectable), podStore: di.inject(podStoreInjectable), jobStore: di.inject(jobStoreInjectable), - getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable), - requestPodMetricsForJobs: di.inject(requestPodMetricsForJobsInjectable), + logger: di.inject(loggerInjectable), }), }); diff --git a/src/renderer/components/+workloads-jobs/jobs.tsx b/src/renderer/components/+workloads-jobs/jobs.tsx index f1455bd2f8..c0bc9e2d66 100644 --- a/src/renderer/components/+workloads-jobs/jobs.tsx +++ b/src/renderer/components/+workloads-jobs/jobs.tsx @@ -35,67 +35,64 @@ interface Dependencies { filterByNamespace: FilterByNamespace; } -@observer -class NonInjectedJobs extends React.Component { - render() { - const { - eventStore, - filterByNamespace, - jobStore, - } = this.props; +const NonInjectedJobs = observer((props: Dependencies) => { + const { + eventStore, + filterByNamespace, + jobStore, + } = props; - return ( - - job.getName(), - [columnId.namespace]: job => job.getNs(), - [columnId.conditions]: job => job.getCondition()?.type, - [columnId.age]: job => -job.getCreationTimestamp(), - }} - searchFilters={[ - job => job.getSearchFields(), - ]} - renderHeaderTitle="Jobs" - renderTableHeader={[ - { title: "Name", className: "name", sortBy: columnId.name, id: columnId.name }, - { title: "Namespace", className: "namespace", sortBy: columnId.namespace, id: columnId.namespace }, - { title: "Completions", className: "completions", id: columnId.completions }, - { className: "warning", showWithColumn: columnId.completions }, - { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, - { title: "Conditions", className: "conditions", sortBy: columnId.conditions, id: columnId.conditions }, - ]} - renderTableContents={job => { - const condition = job.getCondition(); + return ( + + job.getName(), + [columnId.namespace]: job => job.getNs(), + [columnId.conditions]: job => job.getCondition()?.type, + [columnId.age]: job => -job.getCreationTimestamp(), + }} + searchFilters={[ + job => job.getSearchFields(), + ]} + renderHeaderTitle="Jobs" + renderTableHeader={[ + { title: "Name", className: "name", sortBy: columnId.name, id: columnId.name }, + { title: "Namespace", className: "namespace", sortBy: columnId.namespace, id: columnId.namespace }, + { title: "Completions", className: "completions", id: columnId.completions }, + { className: "warning", showWithColumn: columnId.completions }, + { title: "Age", className: "age", sortBy: columnId.age, id: columnId.age }, + { title: "Conditions", className: "conditions", sortBy: columnId.conditions, id: columnId.conditions }, + ]} + renderTableContents={job => { + const condition = job.getCondition(); - return [ - job.getName(), - filterByNamespace(job.getNs()))} - > - {job.getNs()} - , - `${job.getCompletions()} / ${job.getDesiredCompletions()}`, - , - , - condition && { - title: condition.type, - className: kebabCase(condition.type), - }, - ]; - }} - /> - - ); - } -} + return [ + job.getName(), + filterByNamespace(job.getNs()))} + > + {job.getNs()} + , + `${job.getCompletions()} / ${job.getDesiredCompletions()}`, + , + , + condition && { + title: condition.type, + className: kebabCase(condition.type), + }, + ]; + }} + /> + + ); +}); export const Jobs = withInjectables(NonInjectedJobs, { getProps: (di, props) => ({ diff --git a/src/renderer/components/+workloads-jobs/metrics-details-component.injectable.tsx b/src/renderer/components/+workloads-jobs/metrics-details-component.injectable.tsx new file mode 100644 index 0000000000..3b8ab17287 --- /dev/null +++ b/src/renderer/components/+workloads-jobs/metrics-details-component.injectable.tsx @@ -0,0 +1,34 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import React from "react"; +import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; +import type { Job } from "../../../common/k8s-api/endpoints"; +import enabledMetricsInjectable from "../../api/catalog/entity/metrics-enabled.injectable"; +import type { KubeObjectDetailsProps } from "../kube-object-details"; +import { kubeObjectDetailItemInjectionToken } from "../kube-object-details/kube-object-detail-items/kube-object-detail-item-injection-token"; +import { ResourceMetrics } from "../resource-metrics"; +import jobMetricsInjectable from "./metrics.injectable"; + +const jobMetricsDetailsComponentInjectable = getInjectable({ + id: "job-metrics-details-component", + instantiate: (di) => ({ + Component: ({ object }: KubeObjectDetailsProps) => ( + + + + ), + enabled: di.inject(enabledMetricsInjectable, ClusterMetricsResourceType.Job), + orderNumber: -1, + }), + injectionToken: kubeObjectDetailItemInjectionToken, +}); + +export default jobMetricsDetailsComponentInjectable; diff --git a/src/renderer/components/+workloads-jobs/metrics.injectable.ts b/src/renderer/components/+workloads-jobs/metrics.injectable.ts new file mode 100644 index 0000000000..dd0799de90 --- /dev/null +++ b/src/renderer/components/+workloads-jobs/metrics.injectable.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; +import { asyncComputed } from "@ogre-tools/injectable-react"; +import { now } from "mobx-utils"; +import type { Job } from "../../../common/k8s-api/endpoints"; +import requestPodMetricsForJobsInjectable from "../../../common/k8s-api/endpoints/metrics.api/request-pod-metrics-for-jobs.injectable"; + +const jobMetricsInjectable = getInjectable({ + id: "job-metrics", + instantiate: (di, job) => { + const requestPodMetricsForJobs = di.inject(requestPodMetricsForJobsInjectable); + + return asyncComputed(() => { + now(60 * 1000); + + return requestPodMetricsForJobs([job], job.getNs()); + }); + }, + lifecycle: lifecycleEnum.keyedSingleton({ + getInstanceKey: (di, job: Job) => job.getId(), + }), +}); + +export default jobMetricsInjectable;