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

Extract hard-coded cluster overview components as injectables

Signed-off-by: Iku-turso <mikko.aspiala@gmail.com>
This commit is contained in:
Iku-turso 2023-03-16 15:38:33 +02:00
parent fe402fafd5
commit d082a2766c
5 changed files with 483 additions and 422 deletions

View File

@ -1,129 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import styles from "./cluster-metrics.module.scss";
import React, { useState } from "react";
import { observer } from "mobx-react";
import type { ChartOptions, ChartPoint } from "chart.js";
import type { ClusterOverviewStore } from "./cluster-overview-store/cluster-overview-store";
import { MetricType } from "./cluster-overview-store/cluster-overview-store";
import { BarChart } from "../chart";
import { bytesToUnits, cssNames } from "@k8slens/utilities";
import { Spinner } from "../spinner";
import { ZebraStripesPlugin } from "../chart/zebra-stripes.plugin";
import { ClusterNoMetrics } from "./cluster-no-metrics";
import { ClusterMetricSwitchers } from "./cluster-metric-switchers";
import { getMetricLastPoints } from "../../../common/k8s-api/endpoints/metrics.api";
import { withInjectables } from "@ogre-tools/injectable-react";
import clusterOverviewStoreInjectable from "./cluster-overview-store/cluster-overview-store.injectable";
interface Dependencies {
clusterOverviewStore: ClusterOverviewStore;
}
const NonInjectedClusterMetrics = observer(({ clusterOverviewStore: { metricType, metricNodeRole, getMetricsValues, metricsLoaded, metrics }}: Dependencies) => {
const [plugins] = useState([new ZebraStripesPlugin()]);
const { memoryCapacity, cpuCapacity } = getMetricLastPoints(metrics ?? {});
const metricValues = getMetricsValues(metrics ?? {});
const colors = { cpu: "#3D90CE", memory: "#C93DCE" };
const data = metricValues.map(value => ({
x: value[0],
y: parseFloat(value[1]).toFixed(3),
}));
const datasets = [{
id: metricType + metricNodeRole,
label: `${metricType.toUpperCase()} usage`,
borderColor: colors[metricType],
data,
}];
const cpuOptions: ChartOptions = {
scales: {
yAxes: [{
ticks: {
suggestedMax: cpuCapacity,
callback: (value) => value,
},
}],
},
tooltips: {
callbacks: {
label: ({ index }, data) => {
if (!index) {
return "<unknown>";
}
const value = data.datasets?.[0].data?.[index] as ChartPoint;
return value.y?.toString() ?? "<unknown>";
},
},
},
};
const memoryOptions: ChartOptions = {
scales: {
yAxes: [{
ticks: {
suggestedMax: memoryCapacity,
callback: (value: string) => !value ? 0 : bytesToUnits(parseInt(value)),
},
}],
},
tooltips: {
callbacks: {
label: ({ index }, data) => {
if (!index) {
return "<unknown>";
}
const value = data.datasets?.[0].data?.[index] as ChartPoint;
return bytesToUnits(parseInt(value.y as string), { precision: 3 });
},
},
},
};
const options = metricType === MetricType.CPU ? cpuOptions : memoryOptions;
const renderMetrics = () => {
if (!metricValues.length && !metricsLoaded) {
return <Spinner center/>;
}
if (!memoryCapacity || !cpuCapacity) {
return <ClusterNoMetrics className={styles.empty}/>;
}
return (
<BarChart
name={`${metricNodeRole}-${metricType}`}
options={options}
data={{ datasets }}
timeLabelStep={5}
showLegend={false}
plugins={plugins}
className={styles.chart}
/>
);
};
return (
<div className={cssNames(styles.ClusterMetrics, "flex column")}>
<ClusterMetricSwitchers/>
{renderMetrics()}
</div>
);
});
export const ClusterMetrics = withInjectables<Dependencies>(
NonInjectedClusterMetrics,
{
getProps: (di) => ({
clusterOverviewStore: di.inject(clusterOverviewStoreInjectable),
}),
},
);

View File

@ -0,0 +1,161 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import styles from "../cluster-metrics.module.scss";
import React, { useState } from "react";
import { observer } from "mobx-react";
import type { ChartOptions, ChartPoint } from "chart.js";
import type { ClusterOverviewStore } from "../cluster-overview-store/cluster-overview-store";
import { MetricType } from "../cluster-overview-store/cluster-overview-store";
import { BarChart } from "../../chart";
import { bytesToUnits, cssNames } from "@k8slens/utilities";
import { Spinner } from "../../spinner";
import { ZebraStripesPlugin } from "../../chart/zebra-stripes.plugin";
import { ClusterNoMetrics } from "../cluster-no-metrics";
import { ClusterMetricSwitchers } from "../cluster-metric-switchers";
import { getMetricLastPoints } from "../../../../common/k8s-api/endpoints/metrics.api";
import { withInjectables } from "@ogre-tools/injectable-react";
import clusterOverviewStoreInjectable from "../cluster-overview-store/cluster-overview-store.injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { clusterOverviewUIBlockInjectionToken } from "@k8slens/metrics";
interface Dependencies {
clusterOverviewStore: ClusterOverviewStore;
}
const NonInjectedClusterMetrics = observer(
({
clusterOverviewStore: {
metricType,
metricNodeRole,
getMetricsValues,
metricsLoaded,
metrics,
},
}: Dependencies) => {
const [plugins] = useState([new ZebraStripesPlugin()]);
const { memoryCapacity, cpuCapacity } = getMetricLastPoints(metrics ?? {});
const metricValues = getMetricsValues(metrics ?? {});
const colors = { cpu: "#3D90CE", memory: "#C93DCE" };
const data = metricValues.map((value) => ({
x: value[0],
y: parseFloat(value[1]).toFixed(3),
}));
const datasets = [
{
id: metricType + metricNodeRole,
label: `${metricType.toUpperCase()} usage`,
borderColor: colors[metricType],
data,
},
];
const cpuOptions: ChartOptions = {
scales: {
yAxes: [
{
ticks: {
suggestedMax: cpuCapacity,
callback: (value) => value,
},
},
],
},
tooltips: {
callbacks: {
label: ({ index }, data) => {
if (!index) {
return "<unknown>";
}
const value = data.datasets?.[0].data?.[index] as ChartPoint;
return value.y?.toString() ?? "<unknown>";
},
},
},
};
const memoryOptions: ChartOptions = {
scales: {
yAxes: [
{
ticks: {
suggestedMax: memoryCapacity,
callback: (value: string) =>
!value ? 0 : bytesToUnits(parseInt(value)),
},
},
],
},
tooltips: {
callbacks: {
label: ({ index }, data) => {
if (!index) {
return "<unknown>";
}
const value = data.datasets?.[0].data?.[index] as ChartPoint;
return bytesToUnits(parseInt(value.y as string), { precision: 3 });
},
},
},
};
const options = metricType === MetricType.CPU ? cpuOptions : memoryOptions;
const renderMetrics = () => {
if (!metricValues.length && !metricsLoaded) {
return <Spinner center />;
}
if (!memoryCapacity || !cpuCapacity) {
return <ClusterNoMetrics className={styles.empty} />;
}
return (
<BarChart
name={`${metricNodeRole}-${metricType}`}
options={options}
data={{ datasets }}
timeLabelStep={5}
showLegend={false}
plugins={plugins}
className={styles.chart}
/>
);
};
return (
<div className={cssNames(styles.ClusterMetrics, "flex column")}>
<ClusterMetricSwitchers />
{renderMetrics()}
</div>
);
}
);
const ClusterMetrics = withInjectables<Dependencies>(
NonInjectedClusterMetrics,
{
getProps: (di) => ({
clusterOverviewStore: di.inject(clusterOverviewStoreInjectable),
}),
}
);
const clusterMetricsOverviewBlockInjectable = getInjectable({
id: "cluster-metrics-overview-block",
instantiate: () => ({
id: "cluster-metrics-overview-block",
Component: ClusterMetrics,
}),
injectionToken: clusterOverviewUIBlockInjectionToken,
});
export default clusterMetricsOverviewBlockInjectable;

View File

@ -0,0 +1,322 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import styles from "../cluster-pie-charts.module.scss";
import React from "react";
import { observer } from "mobx-react";
import type { ClusterOverviewStore } from "../cluster-overview-store/cluster-overview-store";
import { MetricNodeRole } from "../cluster-overview-store/cluster-overview-store";
import { Spinner } from "../../spinner";
import { Icon } from "../../icon";
import type { NodeStore } from "../../+nodes/store";
import type { PieChartData } from "../../chart";
import { PieChart } from "../../chart";
import { ClusterNoMetrics } from "../cluster-no-metrics";
import { bytesToUnits, cssNames } from "@k8slens/utilities";
import type { LensTheme } from "../../../themes/lens-theme";
import { getMetricLastPoints } from "../../../../common/k8s-api/endpoints/metrics.api";
import { withInjectables } from "@ogre-tools/injectable-react";
import clusterOverviewStoreInjectable from "../cluster-overview-store/cluster-overview-store.injectable";
import nodeStoreInjectable from "../../+nodes/store.injectable";
import type { IComputedValue } from "mobx";
import activeThemeInjectable from "../../../themes/active.injectable";
import type { ClusterMetricData } from "../../../../common/k8s-api/endpoints/metrics.api/request-cluster-metrics-by-node-names.injectable";
import { clusterOverviewUIBlockInjectionToken } from "@k8slens/metrics";
import { getInjectable } from "@ogre-tools/injectable";
function createLabels(rawLabelData: [string, number | undefined][]): string[] {
return rawLabelData.map(
([key, value]) => `${key}: ${value?.toFixed(2) || "N/A"}`
);
}
const checkedBytesToUnits = (value: number | undefined) =>
typeof value === "number" ? bytesToUnits(value) : "N/A";
interface Dependencies {
clusterOverviewStore: ClusterOverviewStore;
nodeStore: NodeStore;
activeTheme: IComputedValue<LensTheme>;
}
const NonInjectedClusterPieCharts = observer(
({ clusterOverviewStore, nodeStore, activeTheme }: Dependencies) => {
const renderLimitWarning = () => {
return (
<div className="node-warning flex gaps align-center">
<Icon material="info" />
<p>Specified limits are higher than node capacity!</p>
</div>
);
};
const renderCharts = (
lastPoints: Partial<Record<keyof ClusterMetricData, number>>
) => {
const {
memoryUsage,
memoryRequests,
memoryAllocatableCapacity,
memoryCapacity,
memoryLimits,
cpuUsage,
cpuRequests,
cpuAllocatableCapacity,
cpuCapacity,
cpuLimits,
podUsage,
podAllocatableCapacity,
podCapacity,
} = lastPoints;
if (
typeof cpuCapacity !== "number" ||
typeof cpuAllocatableCapacity !== "number" ||
typeof podCapacity !== "number" ||
typeof podAllocatableCapacity !== "number" ||
typeof memoryAllocatableCapacity !== "number" ||
typeof memoryCapacity !== "number" ||
typeof memoryUsage !== "number" ||
typeof memoryRequests !== "number"
) {
return null;
}
const defaultColor = activeTheme.get().colors.pieChartDefaultColor;
const cpuData: PieChartData = {
datasets: [
{
data: [cpuUsage, cpuUsage ? cpuAllocatableCapacity - cpuUsage : 1],
backgroundColor: ["#c93dce", defaultColor],
id: "cpuUsage",
label: "Usage",
},
{
data: [
cpuRequests,
cpuRequests ? cpuAllocatableCapacity - cpuRequests : 1,
],
backgroundColor: ["#4caf50", defaultColor],
id: "cpuRequests",
label: "Requests",
},
{
data: [
cpuLimits,
Math.max(
0,
cpuAllocatableCapacity - (cpuLimits ?? cpuAllocatableCapacity)
),
],
backgroundColor: ["#3d90ce", defaultColor],
id: "cpuLimits",
label: "Limits",
},
],
labels: createLabels([
["Usage", cpuUsage],
["Requests", cpuRequests],
["Limits", cpuLimits],
["Allocatable Capacity", cpuAllocatableCapacity],
["Capacity", cpuCapacity],
]),
};
const memoryData: PieChartData = {
datasets: [
{
data: [
memoryUsage,
memoryUsage ? memoryAllocatableCapacity - memoryUsage : 1,
],
backgroundColor: ["#c93dce", defaultColor],
id: "memoryUsage",
label: "Usage",
},
{
data: [
memoryRequests,
memoryRequests ? memoryAllocatableCapacity - memoryRequests : 1,
],
backgroundColor: ["#4caf50", defaultColor],
id: "memoryRequests",
label: "Requests",
},
{
data: [
memoryLimits,
Math.max(
0,
memoryAllocatableCapacity -
(memoryLimits ?? memoryAllocatableCapacity)
),
],
backgroundColor: ["#3d90ce", defaultColor],
id: "memoryLimits",
label: "Limits",
},
],
labels: [
`Usage: ${bytesToUnits(memoryUsage)}`,
`Requests: ${bytesToUnits(memoryRequests)}`,
`Limits: ${checkedBytesToUnits(memoryLimits)}`,
`Allocatable Capacity: ${bytesToUnits(memoryAllocatableCapacity)}`,
`Capacity: ${bytesToUnits(memoryCapacity)}`,
],
};
const podsData: PieChartData = {
datasets: [
{
data: [podUsage, podUsage ? podAllocatableCapacity - podUsage : 1],
backgroundColor: ["#4caf50", defaultColor],
id: "podUsage",
label: "Usage",
tooltipLabels: [
(percent) => `Usage: ${percent}`,
(percent) => `Available: ${percent}`,
],
},
],
labels: [
`Usage: ${podUsage || 0}`,
`Capacity: ${podAllocatableCapacity}`,
],
};
return (
<div className="flex justify-center box grow gaps">
<div
className={cssNames(
styles.chart,
"flex column align-center box grow"
)}
>
<PieChart
data={cpuData}
title="CPU"
legendColors={[
"#c93dce",
"#4caf50",
"#3d90ce",
"#032b4d",
defaultColor,
]}
/>
{(cpuLimits ?? cpuAllocatableCapacity) > cpuAllocatableCapacity &&
renderLimitWarning()}
</div>
<div
className={cssNames(
styles.chart,
"flex column align-center box grow"
)}
>
<PieChart
data={memoryData}
title="Memory"
legendColors={[
"#c93dce",
"#4caf50",
"#3d90ce",
"#032b4d",
defaultColor,
]}
/>
{(memoryLimits ?? memoryAllocatableCapacity) >
memoryAllocatableCapacity && renderLimitWarning()}
</div>
<div
className={cssNames(
styles.chart,
"flex column align-center box grow"
)}
>
<PieChart
data={podsData}
title="Pods"
legendColors={["#4caf50", defaultColor]}
/>
</div>
</div>
);
};
const renderContent = ({
metricNodeRole,
metrics,
}: ClusterOverviewStore) => {
const { masterNodes, workerNodes } = nodeStore;
const nodes =
metricNodeRole === MetricNodeRole.MASTER ? masterNodes : workerNodes;
if (!nodes.length) {
return (
<div
className={cssNames(
styles.empty,
"flex column box grow align-center justify-center"
)}
>
<Icon material="info" />
No Nodes Available.
</div>
);
}
if (!metrics) {
return (
<div
className={cssNames(
styles.empty,
"flex justify-center align-center box grow"
)}
>
<Spinner />
</div>
);
}
const lastPoints = getMetricLastPoints(metrics);
const { memoryCapacity, cpuCapacity, podCapacity } = lastPoints;
if (!memoryCapacity || !cpuCapacity || !podCapacity) {
return (
<div className={styles.noMetrics}>
<ClusterNoMetrics className={styles.empty} />
</div>
);
}
return renderCharts(lastPoints);
};
return <div className="flex">{renderContent(clusterOverviewStore)}</div>;
}
);
const ClusterPieCharts = withInjectables<Dependencies>(
NonInjectedClusterPieCharts,
{
getProps: (di) => ({
clusterOverviewStore: di.inject(clusterOverviewStoreInjectable),
nodeStore: di.inject(nodeStoreInjectable),
activeTheme: di.inject(activeThemeInjectable),
}),
}
);
const clusterPieChartsClusterOverviewInjectable = getInjectable({
id: "cluster-pie-charts-cluster-overview",
instantiate: (di) => ({
id: "cluster-pie-charts-cluster-overview",
Component: ClusterPieCharts,
}),
injectionToken: clusterOverviewUIBlockInjectionToken,
});
export default clusterPieChartsClusterOverviewInjectable;

View File

@ -15,9 +15,7 @@ import { interval } from "@k8slens/utilities";
import { TabLayout } from "../layout/tab-layout";
import { Spinner } from "../spinner";
import { ClusterIssues } from "./cluster-issues";
import { ClusterMetrics } from "./cluster-metrics";
import type { ClusterOverviewStore } from "./cluster-overview-store/cluster-overview-store";
import { ClusterPieCharts } from "./cluster-pie-charts";
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
import type { EventStore } from "../+events/store";
import { withInjectables } from "@ogre-tools/injectable-react";
@ -79,12 +77,9 @@ class NonInjectedClusterOverview extends React.Component<Dependencies> {
return (
<>
<ClusterMetrics/>
{this.props.uiBlocks.map((block) => (
<div key={block.id}>{<block.Component />}</div>
))}
lol
<ClusterPieCharts/>
</>
);
}

View File

@ -1,288 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import styles from "./cluster-pie-charts.module.scss";
import React from "react";
import { observer } from "mobx-react";
import type { ClusterOverviewStore } from "./cluster-overview-store/cluster-overview-store";
import { MetricNodeRole } from "./cluster-overview-store/cluster-overview-store";
import { Spinner } from "../spinner";
import { Icon } from "../icon";
import type { NodeStore } from "../+nodes/store";
import type { PieChartData } from "../chart";
import { PieChart } from "../chart";
import { ClusterNoMetrics } from "./cluster-no-metrics";
import { bytesToUnits, cssNames } from "@k8slens/utilities";
import type { LensTheme } from "../../themes/lens-theme";
import { getMetricLastPoints } from "../../../common/k8s-api/endpoints/metrics.api";
import { withInjectables } from "@ogre-tools/injectable-react";
import clusterOverviewStoreInjectable from "./cluster-overview-store/cluster-overview-store.injectable";
import nodeStoreInjectable from "../+nodes/store.injectable";
import type { IComputedValue } from "mobx";
import activeThemeInjectable from "../../themes/active.injectable";
import type { ClusterMetricData } from "../../../common/k8s-api/endpoints/metrics.api/request-cluster-metrics-by-node-names.injectable";
function createLabels(rawLabelData: [string, number | undefined][]): string[] {
return rawLabelData.map(([key, value]) => `${key}: ${value?.toFixed(2) || "N/A"}`);
}
const checkedBytesToUnits = (value: number | undefined) => (
typeof value === "number"
? bytesToUnits(value)
: "N/A"
);
interface Dependencies {
clusterOverviewStore: ClusterOverviewStore;
nodeStore: NodeStore;
activeTheme: IComputedValue<LensTheme>;
}
const NonInjectedClusterPieCharts = observer(({
clusterOverviewStore,
nodeStore,
activeTheme,
}: Dependencies) => {
const renderLimitWarning = () => {
return (
<div className="node-warning flex gaps align-center">
<Icon material="info"/>
<p>Specified limits are higher than node capacity!</p>
</div>
);
};
const renderCharts = (lastPoints: Partial<Record<keyof ClusterMetricData, number>>) => {
const {
memoryUsage, memoryRequests, memoryAllocatableCapacity, memoryCapacity, memoryLimits,
cpuUsage, cpuRequests, cpuAllocatableCapacity, cpuCapacity, cpuLimits,
podUsage, podAllocatableCapacity, podCapacity,
} = lastPoints;
if (
typeof cpuCapacity !== "number" ||
typeof cpuAllocatableCapacity !== "number" ||
typeof podCapacity !== "number" ||
typeof podAllocatableCapacity !== "number" ||
typeof memoryAllocatableCapacity !== "number" ||
typeof memoryCapacity !== "number" ||
typeof memoryUsage !== "number" ||
typeof memoryRequests !== "number"
) {
return null;
}
const defaultColor = activeTheme.get().colors.pieChartDefaultColor;
const cpuData: PieChartData = {
datasets: [
{
data: [
cpuUsage,
cpuUsage ? cpuAllocatableCapacity - cpuUsage : 1,
],
backgroundColor: [
"#c93dce",
defaultColor,
],
id: "cpuUsage",
label: "Usage",
},
{
data: [
cpuRequests,
cpuRequests ? cpuAllocatableCapacity - cpuRequests : 1,
],
backgroundColor: [
"#4caf50",
defaultColor,
],
id: "cpuRequests",
label: "Requests",
},
{
data: [
cpuLimits,
Math.max(0, cpuAllocatableCapacity - (cpuLimits ?? cpuAllocatableCapacity)),
],
backgroundColor: [
"#3d90ce",
defaultColor,
],
id: "cpuLimits",
label: "Limits",
},
],
labels: createLabels([
["Usage", cpuUsage],
["Requests", cpuRequests],
["Limits", cpuLimits],
["Allocatable Capacity", cpuAllocatableCapacity],
["Capacity", cpuCapacity],
]),
};
const memoryData: PieChartData = {
datasets: [
{
data: [
memoryUsage,
memoryUsage ? memoryAllocatableCapacity - memoryUsage : 1,
],
backgroundColor: [
"#c93dce",
defaultColor,
],
id: "memoryUsage",
label: "Usage",
},
{
data: [
memoryRequests,
memoryRequests ? memoryAllocatableCapacity - memoryRequests : 1,
],
backgroundColor: [
"#4caf50",
defaultColor,
],
id: "memoryRequests",
label: "Requests",
},
{
data: [
memoryLimits,
Math.max(0, memoryAllocatableCapacity - (memoryLimits ?? memoryAllocatableCapacity)),
],
backgroundColor: [
"#3d90ce",
defaultColor,
],
id: "memoryLimits",
label: "Limits",
},
],
labels: [
`Usage: ${bytesToUnits(memoryUsage)}`,
`Requests: ${bytesToUnits(memoryRequests)}`,
`Limits: ${checkedBytesToUnits(memoryLimits)}`,
`Allocatable Capacity: ${bytesToUnits(memoryAllocatableCapacity)}`,
`Capacity: ${bytesToUnits(memoryCapacity)}`,
],
};
const podsData: PieChartData = {
datasets: [
{
data: [
podUsage,
podUsage ? podAllocatableCapacity - podUsage : 1,
],
backgroundColor: [
"#4caf50",
defaultColor,
],
id: "podUsage",
label: "Usage",
tooltipLabels: [
(percent) => `Usage: ${percent}`,
(percent) => `Available: ${percent}`,
],
},
],
labels: [
`Usage: ${podUsage || 0}`,
`Capacity: ${podAllocatableCapacity}`,
],
};
return (
<div className="flex justify-center box grow gaps">
<div className={cssNames(styles.chart, "flex column align-center box grow")}>
<PieChart
data={cpuData}
title="CPU"
legendColors={[
"#c93dce",
"#4caf50",
"#3d90ce",
"#032b4d",
defaultColor,
]}
/>
{((cpuLimits ?? cpuAllocatableCapacity) > cpuAllocatableCapacity) && renderLimitWarning()}
</div>
<div className={cssNames(styles.chart, "flex column align-center box grow")}>
<PieChart
data={memoryData}
title="Memory"
legendColors={[
"#c93dce",
"#4caf50",
"#3d90ce",
"#032b4d",
defaultColor,
]}
/>
{((memoryLimits ?? memoryAllocatableCapacity) > memoryAllocatableCapacity) && renderLimitWarning()}
</div>
<div className={cssNames(styles.chart, "flex column align-center box grow")}>
<PieChart
data={podsData}
title="Pods"
legendColors={["#4caf50", defaultColor]}
/>
</div>
</div>
);
};
const renderContent = ({ metricNodeRole, metrics }: ClusterOverviewStore) => {
const { masterNodes, workerNodes } = nodeStore;
const nodes = metricNodeRole === MetricNodeRole.MASTER ? masterNodes : workerNodes;
if (!nodes.length) {
return (
<div className={cssNames(styles.empty, "flex column box grow align-center justify-center")}>
<Icon material="info"/>
No Nodes Available.
</div>
);
}
if (!metrics) {
return (
<div className={cssNames(styles.empty, "flex justify-center align-center box grow")}>
<Spinner/>
</div>
);
}
const lastPoints = getMetricLastPoints(metrics);
const { memoryCapacity, cpuCapacity, podCapacity } = lastPoints;
if (!memoryCapacity || !cpuCapacity || !podCapacity) {
return (
<div className={styles.noMetrics}>
<ClusterNoMetrics className={styles.empty}/>
</div>
);
}
return renderCharts(lastPoints);
};
return (
<div className="flex">
{renderContent(clusterOverviewStore)}
</div>
);
});
export const ClusterPieCharts = withInjectables<Dependencies>(NonInjectedClusterPieCharts, {
getProps: (di) => ({
clusterOverviewStore: di.inject(clusterOverviewStoreInjectable),
nodeStore: di.inject(nodeStoreInjectable),
activeTheme: di.inject(activeThemeInjectable),
}),
});