diff --git a/src/common/cluster-store/allowed-resources-injection-token.ts b/src/common/cluster-store/allowed-resources-injection-token.ts index ad387d26a2..353d0b309c 100644 --- a/src/common/cluster-store/allowed-resources-injection-token.ts +++ b/src/common/cluster-store/allowed-resources-injection-token.ts @@ -6,8 +6,6 @@ import { getInjectionToken } from "@ogre-tools/injectable"; import type { IComputedValue } from "mobx"; -export const allowedResourcesInjectionToken = getInjectionToken< - IComputedValue> ->({ +export const allowedResourcesInjectionToken = getInjectionToken>>({ id: "allowed-resources", }); diff --git a/src/renderer/components/+workloads-overview/overview-statuses.tsx b/src/renderer/components/+workloads-overview/overview-statuses.tsx index 1a77288c46..2430409d30 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -31,7 +31,7 @@ const NonInjectedOverviewStatuses = observer( - + ))} diff --git a/src/renderer/components/+workloads-overview/overview-workload-status.tsx b/src/renderer/components/+workloads-overview/overview-workload-status.tsx index 52321d3af4..5640326d87 100644 --- a/src/renderer/components/+workloads-overview/overview-workload-status.tsx +++ b/src/renderer/components/+workloads-overview/overview-workload-status.tsx @@ -10,90 +10,105 @@ import capitalize from "lodash/capitalize"; import { observer } from "mobx-react"; import type { DatasetTooltipLabel, PieChartData } from "../chart"; import { PieChart } from "../chart"; -import { cssVar, object } from "../../utils"; -import type { ThemeStore } from "../../themes/store"; +import { object } from "../../utils"; +import type { LensTheme } from "../../themes/store"; import { withInjectables } from "@ogre-tools/injectable-react"; -import themeStoreInjectable from "../../themes/store.injectable"; +import type { PascalCase } from "type-fest"; +import type { IComputedValue } from "mobx"; +import activeThemeInjectable from "../../themes/active.injectable"; +import type { Workload } from "./workloads/workload-injection-token"; + +export type LowercaseOrPascalCase = Lowercase | PascalCase; + +export type WorkloadStatus = Partial, number>>; + +function toLowercase(src: T): Lowercase { + return src.toLowerCase() as Lowercase; +} export interface OverviewWorkloadStatusProps { - status: Partial>; + workload: Workload; } interface Dependencies { - themeStore: ThemeStore; + activeTheme: IComputedValue; } -@observer -class NonInjectedOverviewWorkloadStatus extends React.Component { - private elem: HTMLElement | null = null; +const statusBackgroundColorMapping = { + "running": "colorOk", + "scheduled": "colorOk", + "pending": "colorWarning", + "suspended": "colorWarning", + "evicted": "colorError", + "succeeded": "colorSuccess", + "failed": "colorError", + "terminated": "colorTerminated", + "terminating": "colorTerminated", + "unknown": "colorVague", + "complete": "colorSuccess", +} as const; - renderChart() { - if (!this.elem) { - return null; +const NonInjectedOverviewWorkloadStatus = observer((props: OverviewWorkloadStatusProps & Dependencies) => { + const { + workload, + activeTheme, + } = props; + const chartData: Required = { + labels: [], + datasets: [], + }; + + const statuses = object.entries(workload.status.get()).filter(([, val]) => val > 0); + const theme = activeTheme.get(); + + if (statuses.length === 0) { + chartData.datasets.push({ + data: [1], + backgroundColor: [theme.colors.pieChartDefaultColor], + label: "Empty", + }); + } else { + const data: number[] = []; + const backgroundColor: string[] = []; + const tooltipLabels: DatasetTooltipLabel[] = []; + + for (const [status, value] of statuses) { + data.push(value); + backgroundColor.push(theme.colors[statusBackgroundColorMapping[toLowercase(status)]]); + tooltipLabels.push(percent => `${capitalize(status)}: ${percent}`); + chartData.labels.push(`${capitalize(status)}: ${value}`); } - const cssVars = cssVar(this.elem); - const chartData: Required = { - labels: [], - datasets: [], - }; + chartData.datasets.push({ + data, + backgroundColor, + label: "Status", + tooltipLabels, + }); + } - const statuses = object.entries(this.props.status).filter(([, val]) => val > 0); - - if (statuses.length === 0) { - chartData.datasets.push({ - data: [1], - backgroundColor: [this.props.themeStore.activeTheme.colors.pieChartDefaultColor], - label: "Empty", - }); - } else { - const data: number[] = []; - const backgroundColor: string[] = []; - const tooltipLabels: DatasetTooltipLabel[] = []; - - for (const [status, value] of statuses) { - data.push(value); - backgroundColor.push(cssVars.get(`--workload-status-${status.toLowerCase()}`).toString()); - tooltipLabels.push(percent => `${capitalize(status)}: ${percent}`); - chartData.labels.push(`${capitalize(status)}: ${value}`); - } - - chartData.datasets.push({ - data, - backgroundColor, - label: "Status", - tooltipLabels, - }); - } - - return ( - +
+ - ); - } - - render() { - return ( -
this.elem = e}> -
- {this.renderChart()} -
+ }} + data-testid={`workload-overview-status-chart-${workload.title.toLowerCase().replace(/\s+/, "-")}`} + />
- ); - } -} +
+ ); +}); export const OverviewWorkloadStatus = withInjectables(NonInjectedOverviewWorkloadStatus, { getProps: (di, props) => ({ ...props, - themeStore: di.inject(themeStoreInjectable), + activeTheme: di.inject(activeThemeInjectable), }), }); diff --git a/src/renderer/components/+workloads-overview/overview.tsx b/src/renderer/components/+workloads-overview/overview.tsx index 0510c96bc9..83a2bf9e84 100644 --- a/src/renderer/components/+workloads-overview/overview.tsx +++ b/src/renderer/components/+workloads-overview/overview.tsx @@ -104,7 +104,7 @@ class NonInjectedWorkloadsOverview extends React.Component { render() { return ( -
+
Overview
{this.renderLoadErrors()} diff --git a/src/renderer/components/+workloads-overview/workloads/workload-injection-token.ts b/src/renderer/components/+workloads-overview/workloads/workload-injection-token.ts index 6453efe59b..decb5a1f7c 100644 --- a/src/renderer/components/+workloads-overview/workloads/workload-injection-token.ts +++ b/src/renderer/components/+workloads-overview/workloads/workload-injection-token.ts @@ -4,12 +4,13 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; import type { IComputedValue } from "mobx"; +import type { WorkloadStatus } from "../overview-workload-status"; export interface Workload { resourceName: string; open: () => void; amountOfItems: IComputedValue; - status: IComputedValue>>; + status: IComputedValue; title: string; orderNumber: number; } diff --git a/src/renderer/components/chart/chart.tsx b/src/renderer/components/chart/chart.tsx index 3d00c71aed..3d54b90302 100644 --- a/src/renderer/components/chart/chart.tsx +++ b/src/renderer/components/chart/chart.tsx @@ -36,6 +36,7 @@ export interface ChartProps { redraw?: boolean; // If true - recreate chart instance with no animation title?: string; className?: string; + "data-testid"?: string; } export enum ChartKind { @@ -212,25 +213,26 @@ export class Chart extends React.Component { } render() { - const { width, height, showChart, title, className } = this.props; + const { width, height, showChart, title, className, "data-testid": dataTestId } = this.props; return ( - <> -
- {title &&
{title}
} - {showChart && ( -
- -
-
- )} - {this.renderLegend()} -
- +
+ {title &&
{title}
} + {showChart && ( +
+ +
+
+ )} + {this.renderLegend()} +
); } }