From 5bb631f26724c0babe5e6514fe77cda83d8ff1c4 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Mon, 11 Apr 2022 15:21:18 +0300 Subject: [PATCH] Fix PieChart tooltips (#5223) * Add tooltipLabels field to ChartData Signed-off-by: Alex Andreev * Use tooltipLabels in ClusterPieCharts for pods Signed-off-by: Alex Andreev * Check for tooltipLabels field to assign tooltip text Signed-off-by: Alex Andreev * Use tooltipLabels inside overview charts Signed-off-by: Alex Andreev * Expand workload overview charts to fit tooltips Signed-off-by: Alex Andreev * Move tooltipLabels into chart datasets Signed-off-by: Alex Andreev * Move tooltipLabels prop to PieCharts Signed-off-by: Alex Andreev * Little clean up Signed-off-by: Alex Andreev * Getting back id field to PieChartData interface Signed-off-by: Alex Andreev * Id fix Signed-off-by: Alex Andreev * More clean up Signed-off-by: Alex Andreev Signed-off-by: Jim Ehrismann --- .../+cluster/cluster-pie-charts.tsx | 13 ++++--- .../overview-workload-status.scss | 6 ---- .../overview-workload-status.tsx | 7 ++-- src/renderer/components/chart/pie-chart.tsx | 34 +++++++++++++++---- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/renderer/components/+cluster/cluster-pie-charts.tsx b/src/renderer/components/+cluster/cluster-pie-charts.tsx index f955ece37b..775d3bacf0 100644 --- a/src/renderer/components/+cluster/cluster-pie-charts.tsx +++ b/src/renderer/components/+cluster/cluster-pie-charts.tsx @@ -11,7 +11,8 @@ import { ClusterOverviewStore, MetricNodeRole } from "./cluster-overview-store/c import { Spinner } from "../spinner"; import { Icon } from "../icon"; import { nodesStore } from "../+nodes/nodes.store"; -import { ChartData, PieChart } from "../chart"; +import type { PieChartData } from "../chart"; +import { PieChart } from "../chart"; import { ClusterNoMetrics } from "./cluster-no-metrics"; import { bytesToUnits, cssNames } from "../../utils"; import { ThemeStore } from "../../theme.store"; @@ -47,7 +48,7 @@ const NonInjectedClusterPieCharts = observer(({ clusterOverviewStore }: Dependen const defaultColor = ThemeStore.getInstance().activeTheme.colors.pieChartDefaultColor; if (!memoryCapacity || !cpuCapacity || !podCapacity || !memoryAllocatableCapacity || !cpuAllocatableCapacity || !podAllocatableCapacity) return null; - const cpuData: ChartData = { + const cpuData: PieChartData = { datasets: [ { data: [ @@ -94,7 +95,7 @@ const NonInjectedClusterPieCharts = observer(({ clusterOverviewStore }: Dependen ["Capacity", cpuCapacity], ]), }; - const memoryData: ChartData = { + const memoryData: PieChartData = { datasets: [ { data: [ @@ -141,7 +142,7 @@ const NonInjectedClusterPieCharts = observer(({ clusterOverviewStore }: Dependen `Capacity: ${bytesToUnits(memoryCapacity)}`, ], }; - const podsData: ChartData = { + const podsData: PieChartData = { datasets: [ { data: [ @@ -154,6 +155,10 @@ const NonInjectedClusterPieCharts = observer(({ clusterOverviewStore }: Dependen ], id: "podUsage", label: "Usage", + tooltipLabels: [ + (percent) => `Usage: ${percent}`, + (percent) => `Available: ${percent}`, + ], }, ], labels: [ diff --git a/src/renderer/components/+workloads-overview/overview-workload-status.scss b/src/renderer/components/+workloads-overview/overview-workload-status.scss index 087cd25888..f8b2aadfd5 100644 --- a/src/renderer/components/+workloads-overview/overview-workload-status.scss +++ b/src/renderer/components/+workloads-overview/overview-workload-status.scss @@ -13,10 +13,4 @@ --workload-status-failed: #{$pod-status-failed-color}; --workload-status-terminated: #{$pod-status-terminated-color}; --workload-status-unknown: #{$pod-status-unknown-color}; - - .PieChart { - .chart-container { - width: 110px - } - } } diff --git a/src/renderer/components/+workloads-overview/overview-workload-status.tsx b/src/renderer/components/+workloads-overview/overview-workload-status.tsx index d042ba1597..5a1751f39c 100644 --- a/src/renderer/components/+workloads-overview/overview-workload-status.tsx +++ b/src/renderer/components/+workloads-overview/overview-workload-status.tsx @@ -8,9 +8,9 @@ import "./overview-workload-status.scss"; import React from "react"; import capitalize from "lodash/capitalize"; import { observer } from "mobx-react"; +import type { DatasetTooltipLabel, PieChartData } from "../chart"; import { PieChart } from "../chart"; import { cssVar } from "../../utils"; -import type { ChartData } from "chart.js"; import { ThemeStore } from "../../theme.store"; interface Props { @@ -27,7 +27,7 @@ export class OverviewWorkloadStatus extends React.Component { } const cssVars = cssVar(this.elem); - const chartData: Required = { + const chartData: Required = { labels: [], datasets: [], }; @@ -43,10 +43,12 @@ export class OverviewWorkloadStatus extends React.Component { } 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}`); } @@ -54,6 +56,7 @@ export class OverviewWorkloadStatus extends React.Component { data, backgroundColor, label: "Status", + tooltipLabels, }); } diff --git a/src/renderer/components/chart/pie-chart.tsx b/src/renderer/components/chart/pie-chart.tsx index 3c5f0a9e19..23eb4dd9c6 100644 --- a/src/renderer/components/chart/pie-chart.tsx +++ b/src/renderer/components/chart/pie-chart.tsx @@ -14,6 +14,17 @@ import { ThemeStore } from "../../theme.store"; interface Props extends ChartProps { } +export interface PieChartData extends ChartJS.ChartData { + datasets?: PieChartDataSets[]; +} + +export type DatasetTooltipLabel = (percent: string) => string | string; + +interface PieChartDataSets extends ChartJS.ChartDataSets { + id?: string; + tooltipLabels?: DatasetTooltipLabel[]; +} + @observer export class PieChart extends React.Component { render() { @@ -26,15 +37,24 @@ export class PieChart extends React.Component { mode: "index", callbacks: { title: () => "", - label: (tooltipItem, data) => { - const dataset: any = data["datasets"][tooltipItem.datasetIndex]; - const metaData = Object.values<{ total: number }>(dataset["_meta"])[0]; - const percent = Math.round((dataset["data"][tooltipItem["index"]] / metaData.total) * 100); - const label = dataset["label"]; + label: (tooltipItem, data: PieChartData) => { + const dataset = data.datasets[tooltipItem.datasetIndex]; + const datasetData = dataset.data as number[]; + const total = datasetData.reduce((acc, cur) => acc + cur, 0); + const percent = Math.round((datasetData[tooltipItem.index] as number / total) * 100); + const percentLabel = isNaN(percent) ? "N/A" : `${percent}%`; + const tooltipLabel = dataset.tooltipLabels?.[tooltipItem.index]; + let tooltip = `${dataset.label}: ${percentLabel}`; - if (isNaN(percent)) return `${label}: N/A`; + if (tooltipLabel) { + if (typeof tooltipLabel === "function") { + tooltip = tooltipLabel(percentLabel); + } else { + tooltip = tooltipLabel; + } + } - return `${label}: ${percent}%`; + return tooltip; }, }, filter: ({ datasetIndex, index }, { datasets }) => {