diff --git a/src/renderer/components/+namespaces/metrics-details-component.tsx b/src/renderer/components/+namespaces/metrics-details-component.tsx new file mode 100644 index 0000000000..0ee30b4986 --- /dev/null +++ b/src/renderer/components/+namespaces/metrics-details-component.tsx @@ -0,0 +1,46 @@ +/** + * 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 { asyncComputed } from "@ogre-tools/injectable-react"; +import { computed } from "mobx"; +import { now } from "mobx-utils"; +import React from "react"; +import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; +import { ClusterMetricsResourceType } from "../../../common/cluster-types"; +import type { Namespace } from "../../../common/k8s-api/endpoints"; +import requestPodMetricsInNamespaceInjectable from "../../../common/k8s-api/endpoints/metrics.api/request-pod-metrics-in-namespace.injectable"; +import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.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"; + +const namespaceMetricsDetailsComponentInjectable = getInjectable({ + id: "namespace-metrics-details-component", + instantiate: (di) => { + const getActiveClusterEntity = di.inject(getActiveClusterEntityInjectable); + const requestPodMetricsInNamespace = di.inject(requestPodMetricsInNamespaceInjectable); + + return { + Component: (props: KubeObjectDetailsProps) => ( + { + now(60 * 1000); // Update every minute + + return requestPodMetricsInNamespace(props.object.getName()); + })} + > + + + ), + enabled: computed(() => !getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.Namespace)), + orderNumber: -1, + }; + }, + injectionToken: kubeObjectDetailItemInjectionToken, +}); + +export default namespaceMetricsDetailsComponentInjectable; diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index a11d7f26a5..33712e9b2b 100644 --- a/src/renderer/components/+namespaces/namespace-details.tsx +++ b/src/renderer/components/+namespaces/namespace-details.tsx @@ -6,7 +6,7 @@ import "./namespace-details.scss"; import React from "react"; -import { computed, makeObservable, observable, reaction } from "mobx"; +import { computed, makeObservable } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem } from "../drawer"; import { cssNames } from "../../utils"; @@ -14,42 +14,32 @@ import { Namespace } from "../../../common/k8s-api/endpoints"; import type { KubeObjectDetailsProps } from "../kube-object-details"; import { Link } from "react-router-dom"; import { Spinner } from "../spinner"; -import { KubeObjectMeta } from "../kube-object-meta"; -import { ResourceMetrics } from "../resource-metrics"; -import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; -import { ClusterMetricsResourceType } from "../../../common/cluster-types"; -import 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 { GetActiveClusterEntity } from "../../api/catalog/entity/get-active-cluster-entity.injectable"; import type { GetDetailsUrl } from "../kube-detail-params/get-details-url.injectable"; import type { ResourceQuotaStore } from "../+config-resource-quotas/store"; import type { LimitRangeStore } from "../+config-limit-ranges/store"; -import getActiveClusterEntityInjectable from "../../api/catalog/entity/get-active-cluster-entity.injectable"; import getDetailsUrlInjectable from "../kube-detail-params/get-details-url.injectable"; import limitRangeStoreInjectable from "../+config-limit-ranges/store.injectable"; import resourceQuotaStoreInjectable from "../+config-resource-quotas/store.injectable"; -import type { PodMetricInNamespaceData, RequestPodMetricsInNamespace } from "../../../common/k8s-api/endpoints/metrics.api/request-pod-metrics-in-namespace.injectable"; -import requestPodMetricsInNamespaceInjectable from "../../../common/k8s-api/endpoints/metrics.api/request-pod-metrics-in-namespace.injectable"; +import type { Logger } from "../../../common/logger"; +import loggerInjectable from "../../../common/logger.injectable"; export interface NamespaceDetailsProps extends KubeObjectDetailsProps { } interface Dependencies { subscribeStores: SubscribeStores; - getActiveClusterEntity: GetActiveClusterEntity; getDetailsUrl: GetDetailsUrl; resourceQuotaStore: ResourceQuotaStore; limitRangeStore: LimitRangeStore; - requestPodMetricsInNamespace: RequestPodMetricsInNamespace; + logger: Logger; } @observer class NonInjectedNamespaceDetails extends React.Component { - @observable metrics: PodMetricInNamespaceData | null = null; - constructor(props: NamespaceDetailsProps & Dependencies) { super(props); makeObservable(this); @@ -57,10 +47,6 @@ class NonInjectedNamespaceDetails extends React.Component this.props.object, () => { - this.metrics = null; - }), - this.props.subscribeStores([ this.props.resourceQuotaStore, this.props.limitRangeStore, @@ -80,40 +66,23 @@ class NonInjectedNamespaceDetails extends React.Component { - this.metrics = await this.props.requestPodMetricsInNamespace(this.props.object.getName()); - }; - render() { - const { object: namespace, getActiveClusterEntity, resourceQuotaStore, getDetailsUrl, limitRangeStore } = this.props; + const { object: namespace, resourceQuotaStore, getDetailsUrl, limitRangeStore } = this.props; if (!namespace) { return null; } if (!(namespace instanceof Namespace)) { - logger.error("[NamespaceDetails]: passed object that is not an instanceof Namespace", namespace); + this.props.logger.error("[NamespaceDetails]: passed object that is not an instanceof Namespace", namespace); return null; } const status = namespace.getStatus(); - const isMetricHidden = getActiveClusterEntity()?.isMetricHidden(ClusterMetricsResourceType.Namespace); return (
- {!isMetricHidden && ( - - - - )} - - {status} @@ -143,11 +112,10 @@ export const NamespaceDetails = withInjectables ({ ...props, subscribeStores: di.inject(subscribeStoresInjectable), - getActiveClusterEntity: di.inject(getActiveClusterEntityInjectable), getDetailsUrl: di.inject(getDetailsUrlInjectable), limitRangeStore: di.inject(limitRangeStoreInjectable), resourceQuotaStore: di.inject(resourceQuotaStoreInjectable), - requestPodMetricsInNamespace: di.inject(requestPodMetricsInNamespaceInjectable), + logger: di.inject(loggerInjectable), }), }); diff --git a/src/renderer/components/resource-metrics/resource-metrics.tsx b/src/renderer/components/resource-metrics/resource-metrics.tsx index b845d8a4c1..195c97d35b 100644 --- a/src/renderer/components/resource-metrics/resource-metrics.tsx +++ b/src/renderer/components/resource-metrics/resource-metrics.tsx @@ -5,24 +5,22 @@ import "./resource-metrics.scss"; -import React, { createContext, useEffect, useState } from "react"; +import React, { createContext, useState } from "react"; import { Radio, RadioGroup } from "../radio"; -import { useInterval } from "../../hooks"; import type { KubeObject } from "../../../common/k8s-api/kube-object"; -import { cssNames, noop } from "../../utils"; +import { cssNames } from "../../utils"; import { Spinner } from "../spinner"; import type { MetricsTab } from "../chart/options"; import type { MetricData } from "../../../common/k8s-api/endpoints/metrics.api"; +import type { IAsyncComputed } from "@ogre-tools/injectable-react"; export type AtLeastOneMetricTab = [MetricsTab, ...MetricsTab[]]; export interface ResourceMetricsProps { tabs: AtLeastOneMetricTab; object: KubeObject; - loader?: () => void; - interval?: number; className?: string; - metrics: Partial> | null | undefined; + metrics: IAsyncComputed> | null | undefined>; children: React.ReactChild | React.ReactChild[]; } @@ -34,48 +32,41 @@ export interface ResourceMetricsValue { export const ResourceMetricsContext = createContext(null); -export function ResourceMetrics({ object, loader = noop, interval = 60, tabs, children, className, metrics }: ResourceMetricsProps) { +export function ResourceMetrics({ object, tabs, children, className, metrics }: ResourceMetricsProps) { const [tab, setTab] = useState(tabs[0]); - // This is done just incase `loader` is actually something like `() => Promise` - useEffect(() => void loader(), [object]); - useInterval(loader, interval * 1000); - - const renderContents = () => { - return ( - <> -
- - {tabs.map((tab, index) => ( - - ))} - -
- -
- {children} -
-
-
- -
- - ); - }; - return (
- {renderContents()} +
+ + {tabs.map((tab, index) => ( + + ))} + +
+ +
+ {children} +
+
+
+ +
); }