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

Fix OverviewWorkloadStatus to satisfy tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-06-24 13:59:13 -04:00
parent 4d19a4ed47
commit ed48d1611f
6 changed files with 106 additions and 90 deletions

View File

@ -6,8 +6,6 @@
import { getInjectionToken } from "@ogre-tools/injectable"; import { getInjectionToken } from "@ogre-tools/injectable";
import type { IComputedValue } from "mobx"; import type { IComputedValue } from "mobx";
export const allowedResourcesInjectionToken = getInjectionToken< export const allowedResourcesInjectionToken = getInjectionToken<IComputedValue<Set<string>>>({
IComputedValue<Set<string>>
>({
id: "allowed-resources", id: "allowed-resources",
}); });

View File

@ -31,7 +31,7 @@ const NonInjectedOverviewStatuses = observer(
</a> </a>
</div> </div>
<OverviewWorkloadStatus status={workload.status.get()} /> <OverviewWorkloadStatus workload={workload} />
</div> </div>
))} ))}
</div> </div>

View File

@ -10,40 +10,61 @@ import capitalize from "lodash/capitalize";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import type { DatasetTooltipLabel, PieChartData } from "../chart"; import type { DatasetTooltipLabel, PieChartData } from "../chart";
import { PieChart } from "../chart"; import { PieChart } from "../chart";
import { cssVar, object } from "../../utils"; import { object } from "../../utils";
import type { ThemeStore } from "../../themes/store"; import type { LensTheme } from "../../themes/store";
import { withInjectables } from "@ogre-tools/injectable-react"; 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<T extends string> = Lowercase<T> | PascalCase<T>;
export type WorkloadStatus = Partial<Record<LowercaseOrPascalCase<keyof typeof statusBackgroundColorMapping>, number>>;
function toLowercase<T extends string>(src: T): Lowercase<T> {
return src.toLowerCase() as Lowercase<T>;
}
export interface OverviewWorkloadStatusProps { export interface OverviewWorkloadStatusProps {
status: Partial<Record<string, number>>; workload: Workload;
} }
interface Dependencies { interface Dependencies {
themeStore: ThemeStore; activeTheme: IComputedValue<LensTheme>;
} }
@observer const statusBackgroundColorMapping = {
class NonInjectedOverviewWorkloadStatus extends React.Component<OverviewWorkloadStatusProps & Dependencies> { "running": "colorOk",
private elem: HTMLElement | null = null; "scheduled": "colorOk",
"pending": "colorWarning",
"suspended": "colorWarning",
"evicted": "colorError",
"succeeded": "colorSuccess",
"failed": "colorError",
"terminated": "colorTerminated",
"terminating": "colorTerminated",
"unknown": "colorVague",
"complete": "colorSuccess",
} as const;
renderChart() { const NonInjectedOverviewWorkloadStatus = observer((props: OverviewWorkloadStatusProps & Dependencies) => {
if (!this.elem) { const {
return null; workload,
} activeTheme,
} = props;
const cssVars = cssVar(this.elem);
const chartData: Required<PieChartData> = { const chartData: Required<PieChartData> = {
labels: [], labels: [],
datasets: [], datasets: [],
}; };
const statuses = object.entries(this.props.status).filter(([, val]) => val > 0); const statuses = object.entries(workload.status.get()).filter(([, val]) => val > 0);
const theme = activeTheme.get();
if (statuses.length === 0) { if (statuses.length === 0) {
chartData.datasets.push({ chartData.datasets.push({
data: [1], data: [1],
backgroundColor: [this.props.themeStore.activeTheme.colors.pieChartDefaultColor], backgroundColor: [theme.colors.pieChartDefaultColor],
label: "Empty", label: "Empty",
}); });
} else { } else {
@ -53,7 +74,7 @@ class NonInjectedOverviewWorkloadStatus extends React.Component<OverviewWorkload
for (const [status, value] of statuses) { for (const [status, value] of statuses) {
data.push(value); data.push(value);
backgroundColor.push(cssVars.get(`--workload-status-${status.toLowerCase()}`).toString()); backgroundColor.push(theme.colors[statusBackgroundColorMapping[toLowercase(status)]]);
tooltipLabels.push(percent => `${capitalize(status)}: ${percent}`); tooltipLabels.push(percent => `${capitalize(status)}: ${percent}`);
chartData.labels.push(`${capitalize(status)}: ${value}`); chartData.labels.push(`${capitalize(status)}: ${value}`);
} }
@ -67,6 +88,8 @@ class NonInjectedOverviewWorkloadStatus extends React.Component<OverviewWorkload
} }
return ( return (
<div className="OverviewWorkloadStatus">
<div className="flex column align-center box grow">
<PieChart <PieChart
data={chartData} data={chartData}
options={{ options={{
@ -76,24 +99,16 @@ class NonInjectedOverviewWorkloadStatus extends React.Component<OverviewWorkload
}, },
}, },
}} }}
data-testid={`workload-overview-status-chart-${workload.title.toLowerCase().replace(/\s+/, "-")}`}
/> />
);
}
render() {
return (
<div className="OverviewWorkloadStatus" ref={e => this.elem = e}>
<div className="flex column align-center box grow">
{this.renderChart()}
</div> </div>
</div> </div>
); );
} });
}
export const OverviewWorkloadStatus = withInjectables<Dependencies, OverviewWorkloadStatusProps>(NonInjectedOverviewWorkloadStatus, { export const OverviewWorkloadStatus = withInjectables<Dependencies, OverviewWorkloadStatusProps>(NonInjectedOverviewWorkloadStatus, {
getProps: (di, props) => ({ getProps: (di, props) => ({
...props, ...props,
themeStore: di.inject(themeStoreInjectable), activeTheme: di.inject(activeThemeInjectable),
}), }),
}); });

View File

@ -104,7 +104,7 @@ class NonInjectedWorkloadsOverview extends React.Component<Dependencies> {
render() { render() {
return ( return (
<SiblingsInTabLayout> <SiblingsInTabLayout>
<div className="WorkloadsOverview flex column gaps"> <div className="WorkloadsOverview flex column gaps" data-testid="page-for-workloads-overview">
<div className="header flex gaps align-center"> <div className="header flex gaps align-center">
<h5 className="box grow">Overview</h5> <h5 className="box grow">Overview</h5>
{this.renderLoadErrors()} {this.renderLoadErrors()}

View File

@ -4,12 +4,13 @@
*/ */
import { getInjectionToken } from "@ogre-tools/injectable"; import { getInjectionToken } from "@ogre-tools/injectable";
import type { IComputedValue } from "mobx"; import type { IComputedValue } from "mobx";
import type { WorkloadStatus } from "../overview-workload-status";
export interface Workload { export interface Workload {
resourceName: string; resourceName: string;
open: () => void; open: () => void;
amountOfItems: IComputedValue<number>; amountOfItems: IComputedValue<number>;
status: IComputedValue<Partial<Record<string, number>>>; status: IComputedValue<WorkloadStatus>;
title: string; title: string;
orderNumber: number; orderNumber: number;
} }

View File

@ -36,6 +36,7 @@ export interface ChartProps {
redraw?: boolean; // If true - recreate chart instance with no animation redraw?: boolean; // If true - recreate chart instance with no animation
title?: string; title?: string;
className?: string; className?: string;
"data-testid"?: string;
} }
export enum ChartKind { export enum ChartKind {
@ -212,11 +213,13 @@ export class Chart extends React.Component<ChartProps> {
} }
render() { render() {
const { width, height, showChart, title, className } = this.props; const { width, height, showChart, title, className, "data-testid": dataTestId } = this.props;
return ( return (
<> <div
<div className={cssNames("Chart", className)}> className={cssNames("Chart", className)}
data-testid={dataTestId}
>
{title && <div className="chart-title">{title}</div>} {title && <div className="chart-title">{title}</div>}
{showChart && ( {showChart && (
<div className="chart-container"> <div className="chart-container">
@ -230,7 +233,6 @@ export class Chart extends React.Component<ChartProps> {
)} )}
{this.renderLegend()} {this.renderLegend()}
</div> </div>
</>
); );
} }
} }