Skip to content

Commit b5a82fb

Browse files
ammont82openshift-merge-bot[bot]
authored andcommitted
ECOPROJECT-3795 | refactor: change empty state for cards without data
- New CardEmptyState component created - Default description: "This data is not available for older inventories or certain imported reports." - MigrationDonutChart now renders CardEmptyState when chart data is empty with configurable emptyStateTitle and emptyStateDescription props Signed-off-by: Montse Ortega <mortegag@redhat.com>
1 parent a20b888 commit b5a82fb

11 files changed

Lines changed: 119 additions & 28 deletions
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { css } from "@emotion/css";
2+
import { EmptyState, EmptyStateBody } from "@patternfly/react-core";
3+
import { RhUiSearchIcon } from "@patternfly/react-icons";
4+
import React from "react";
5+
6+
export const CARD_EMPTY_STATE_DESCRIPTION =
7+
"This data is not available for older inventories or certain imported reports.";
8+
9+
const cardEmptyStateContainer = css`
10+
display: flex;
11+
flex-direction: column;
12+
justify-content: center;
13+
flex: 1;
14+
min-height: 250px;
15+
`;
16+
17+
export interface CardEmptyStateProps {
18+
title: string;
19+
description?: string;
20+
}
21+
22+
export const CardEmptyState: React.FC<CardEmptyStateProps> = ({
23+
title,
24+
description = CARD_EMPTY_STATE_DESCRIPTION,
25+
}) => {
26+
return (
27+
<div className={cardEmptyStateContainer}>
28+
<EmptyState
29+
headingLevel="h4"
30+
icon={RhUiSearchIcon}
31+
titleText={title}
32+
variant="sm"
33+
>
34+
<EmptyStateBody>{description}</EmptyStateBody>
35+
</EmptyState>
36+
</div>
37+
);
38+
};
39+
40+
CardEmptyState.displayName = "CardEmptyState";

src/ui/core/components/MigrationDonutChart.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { ChartDonut, ChartLabel, ChartLegend } from "@patternfly/react-charts";
22
import { Flex, FlexItem } from "@patternfly/react-core";
33
import React, { useCallback, useMemo } from "react";
44

5+
import { CardEmptyState } from "./CardEmptyState";
6+
57
interface OSData {
68
name: string;
79
count: number;
@@ -45,6 +47,8 @@ interface MigrationDonutChartProps {
4547
percent: number;
4648
total: number;
4749
}) => string;
50+
emptyStateTitle?: string;
51+
emptyStateDescription?: string;
4852
}
4953

5054
const legendColors = [
@@ -76,6 +80,8 @@ const MigrationDonutChart: React.FC<MigrationDonutChartProps> = ({
7680
donutThickness = 45,
7781
padAngle = 1,
7882
tooltipLabelFormatter,
83+
emptyStateTitle = "Data not collected",
84+
emptyStateDescription,
7985
}: MigrationDonutChartProps) => {
8086
const dynamicLegend = useMemo<Record<string, string>>(() => {
8187
const legendMap: Record<string, string> = {};
@@ -152,9 +158,10 @@ const MigrationDonutChart: React.FC<MigrationDonutChartProps> = ({
152158

153159
if (!data || data.length === 0) {
154160
return (
155-
<div style={{ padding: "20px", textAlign: "center" }}>
156-
No data available
157-
</div>
161+
<CardEmptyState
162+
title={emptyStateTitle}
163+
description={emptyStateDescription}
164+
/>
158165
);
159166
}
160167

src/ui/report/views/assessment-report/ClustersOverview.tsx

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import {
1414
} from "@patternfly/react-core";
1515
import React, { useMemo, useState } from "react";
1616

17+
import { CardEmptyState } from "../../../core/components/CardEmptyState";
1718
import MigrationDonutChart from "../../../core/components/MigrationDonutChart";
19+
import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants";
1820
import { dashboardCard } from "./styles";
1921

2022
// ---------------------------------------------------------------------------
@@ -539,6 +541,7 @@ export const ClustersOverview: React.FC<ClustersOverviewProps> = ({
539541
itemsPerRow={Math.ceil(vmByClusterData.chartData.length / 2)}
540542
labelFontSize={18}
541543
marginLeft="12%"
544+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.clusters}
542545
tooltipLabelFormatter={({ datum, percent }) =>
543546
`${datum.countDisplay}\n${percent.toFixed(1)}%`
544547
}
@@ -565,6 +568,7 @@ export const ClustersOverview: React.FC<ClustersOverviewProps> = ({
565568
)}
566569
labelFontSize={17}
567570
marginLeft="0%"
571+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.clusters}
568572
tooltipLabelFormatter={({ datum, percent }) =>
569573
`${datum.countDisplay}\n${percent.toFixed(1)}%`
570574
}
@@ -577,14 +581,9 @@ export const ClustersOverview: React.FC<ClustersOverviewProps> = ({
577581
{VIEW_MODE_LABELS["cpuOverCommitment"]}
578582
</div>
579583
{cpuOverCommitmentData.chartData.length === 0 ? (
580-
<div
581-
style={{
582-
color: "var(--pf-t--global--text--color--subtle)",
583-
textAlign: "center",
584-
}}
585-
>
586-
This inventory has no cpuOverCommitment information.
587-
</div>
584+
<CardEmptyState
585+
title={REPORT_CARD_EMPTY_STATE_TITLES.cpuOvercommitment}
586+
/>
588587
) : (
589588
<>
590589
<div className={cpuOvercommitBoxes}>
@@ -630,14 +629,9 @@ export const ClustersOverview: React.FC<ClustersOverviewProps> = ({
630629
) : viewMode === "cpuOverCommitment" ? (
631630
<>
632631
{chartData.length === 0 ? (
633-
<div
634-
style={{
635-
color: "var(--pf-t--global--text--color--subtle)",
636-
textAlign: "center",
637-
}}
638-
>
639-
This inventory has no cpuOverCommitment information.
640-
</div>
632+
<CardEmptyState
633+
title={REPORT_CARD_EMPTY_STATE_TITLES.cpuOvercommitment}
634+
/>
641635
) : (
642636
<>
643637
<div className={cpuOvercommitBoxes}>
@@ -684,6 +678,7 @@ export const ClustersOverview: React.FC<ClustersOverviewProps> = ({
684678
itemsPerRow={Math.ceil(chartData.length / 2)}
685679
labelFontSize={viewMode === "vmByCluster" ? 18 : 17}
686680
marginLeft={viewMode === "vmByCluster" ? "12%" : "0%"}
681+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.clusters}
687682
tooltipLabelFormatter={({ datum, percent }) =>
688683
`${datum.countDisplay}\n${percent.toFixed(1)}%`
689684
}

src/ui/report/views/assessment-report/CpuAndMemoryOverview.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import React, { useMemo, useState } from "react";
1414

1515
import MigrationDonutChart from "../../../core/components/MigrationDonutChart";
16+
import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants";
1617
import { dashboardCard } from "./styles";
1718

1819
interface CpuAndMemoryOverviewProps {
@@ -240,6 +241,7 @@ export const CpuAndMemoryOverview: React.FC<CpuAndMemoryOverviewProps> = ({
240241
itemsPerRow={Math.ceil(memorySlices.length / 2)}
241242
labelFontSize={18}
242243
marginLeft="0%"
244+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.memory}
243245
tooltipLabelFormatter={({ datum, percent }) =>
244246
`${datum.countDisplay}\n${percent.toFixed(1)}%`
245247
}
@@ -269,6 +271,7 @@ export const CpuAndMemoryOverview: React.FC<CpuAndMemoryOverviewProps> = ({
269271
itemsPerRow={Math.ceil(vcpuSlices.length / 2)}
270272
labelFontSize={18}
271273
marginLeft="52%"
274+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.cpu}
272275
tooltipLabelFormatter={({ datum, percent }) =>
273276
`${datum.countDisplay}\n${percent.toFixed(1)}%`
274277
}
@@ -297,6 +300,11 @@ export const CpuAndMemoryOverview: React.FC<CpuAndMemoryOverviewProps> = ({
297300
itemsPerRow={Math.ceil(activeSlices.length / 2)}
298301
labelFontSize={18}
299302
marginLeft="52%"
303+
emptyStateTitle={
304+
viewMode === "memoryTiers"
305+
? REPORT_CARD_EMPTY_STATE_TITLES.memory
306+
: REPORT_CARD_EMPTY_STATE_TITLES.cpu
307+
}
300308
tooltipLabelFormatter={({ datum, percent }) =>
301309
`${datum.countDisplay}\n${percent.toFixed(1)}%`
302310
}

src/ui/report/views/assessment-report/HostsOverview.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import React, { useMemo } from "react";
1010

1111
import MigrationDonutChart from "../../../core/components/MigrationDonutChart";
12+
import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants";
1213
import { dashboardCard } from "./styles";
1314

1415
type HostLike = {
@@ -138,6 +139,7 @@ export const HostsOverview: React.FC<HostsOverviewProps> = ({
138139
itemsPerRow={2}
139140
labelFontSize={16}
140141
marginLeft="0%"
142+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.hosts}
141143
tooltipLabelFormatter={({ datum, percent }) =>
142144
`${datum.countDisplay}\n${percent.toFixed(1)}%`
143145
}

src/ui/report/views/assessment-report/NetworkOverview.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import React, { useMemo, useState } from "react";
1818

1919
import MigrationDonutChart from "../../../core/components/MigrationDonutChart";
20+
import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants";
2021
import { dashboardCard } from "./styles";
2122

2223
// Reuse an extended palette similar to ClustersOverview to provide stable colors
@@ -330,6 +331,7 @@ export const NetworkOverview: React.FC<NetworkOverviewProps> = ({
330331
subTitleColor="var(--pf-t--global--text--color--subtle)"
331332
itemsPerRow={Math.ceil(chartData.length / 2)}
332333
labelFontSize={18}
334+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.networks}
333335
tooltipLabelFormatter={({ datum, percent }) =>
334336
`${datum.countDisplay}\n${percent.toFixed(1)}%\nVLAN: ${legendVlanMap[datum.legendCategory] ?? "-"}`
335337
}
@@ -351,6 +353,7 @@ export const NetworkOverview: React.FC<NetworkOverviewProps> = ({
351353
subTitleColor="var(--pf-t--global--text--color--subtle)"
352354
itemsPerRow={Math.ceil((nicChartData?.length ?? 0) / 2)}
353355
labelFontSize={18}
356+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.nicCount}
354357
tooltipLabelFormatter={({ datum, percent }) =>
355358
`${datum.countDisplay}\n${percent.toFixed(1)}%`
356359
}
@@ -372,6 +375,7 @@ export const NetworkOverview: React.FC<NetworkOverviewProps> = ({
372375
subTitleColor="var(--pf-t--global--text--color--subtle)"
373376
itemsPerRow={Math.ceil(chartData.length / 2)}
374377
labelFontSize={18}
378+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.networks}
375379
tooltipLabelFormatter={({ datum, percent }) =>
376380
`${datum.countDisplay}\n${percent.toFixed(1)}%\nVLAN: ${legendVlanMap[datum.legendCategory] ?? "-"}`
377381
}
@@ -390,6 +394,7 @@ export const NetworkOverview: React.FC<NetworkOverviewProps> = ({
390394
subTitleColor="var(--pf-t--global--text--color--subtle)"
391395
itemsPerRow={Math.ceil((nicChartData?.length ?? 0) / 2)}
392396
labelFontSize={18}
397+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.nicCount}
393398
tooltipLabelFormatter={({ datum, percent }) =>
394399
`${datum.countDisplay}\n${percent.toFixed(1)}%`
395400
}

src/ui/report/views/assessment-report/OSDistribution.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ import {
1111
import { RhUiInformationFillIcon } from "@patternfly/react-icons";
1212
import React from "react";
1313

14+
import { CardEmptyState } from "../../../core/components/CardEmptyState";
1415
import MigrationChart from "../../../core/components/MigrationChart";
15-
import { chartColorFailure, chartColorSuccess } from "./constants";
16+
import {
17+
chartColorFailure,
18+
chartColorSuccess,
19+
REPORT_CARD_EMPTY_STATE_TITLES,
20+
} from "./constants";
1621
import { dashboardCard } from "./styles";
1722

1823
interface OSDistributionProps {
@@ -109,6 +114,12 @@ export const OSBarChart: React.FC<OSBarChartProps> = ({
109114
infoText: osInfo.upgradeRecommendation,
110115
}));
111116

117+
if (chartData.length === 0) {
118+
return (
119+
<CardEmptyState title={REPORT_CARD_EMPTY_STATE_TITLES.operatingSystems} />
120+
);
121+
}
122+
112123
// Define custom colors: green for supported, red for not supported
113124
const customLegend = {
114125
"Supported by MTV": chartColorSuccess,

src/ui/report/views/assessment-report/StorageOverview.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ import {
2626
} from "@patternfly/react-core";
2727
import React, { useMemo, useState } from "react";
2828

29+
import { CardEmptyState } from "../../../core/components/CardEmptyState";
2930
import MigrationDonutChart from "../../../core/components/MigrationDonutChart";
31+
import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants";
3032
import {
3133
dashboardCard,
3234
storageCardOverflowHidden,
@@ -36,7 +38,6 @@ import {
3638
storageExportSectionTitle,
3739
storageFlexFullWidth,
3840
storageMenuToggleMinWidth,
39-
storageNoDataContainer,
4041
storageTotalsNote,
4142
} from "./styles";
4243

@@ -408,7 +409,9 @@ export const StorageOverview: React.FC<StorageOverviewProps> = ({
408409
{!isExportMode || !exportAllViews ? (
409410
viewMode === "vmCountByDiskType" ? (
410411
diskTypeChartData.length === 0 ? (
411-
<div className={storageNoDataContainer}>No Data Available</div>
412+
<CardEmptyState
413+
title={REPORT_CARD_EMPTY_STATE_TITLES.diskTypes}
414+
/>
412415
) : (
413416
<>
414417
<div className={storageChartWrapper}>
@@ -491,6 +494,7 @@ export const StorageOverview: React.FC<StorageOverviewProps> = ({
491494
itemsPerRow={Math.ceil(sharedDisksChartData.length / 2)}
492495
labelFontSize={18}
493496
marginLeft="52%"
497+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.storage}
494498
tooltipLabelFormatter={({ datum, percent }) =>
495499
`${datum.countDisplay}\n${percent.toFixed(1)}%`
496500
}
@@ -516,6 +520,7 @@ export const StorageOverview: React.FC<StorageOverviewProps> = ({
516520
itemsPerRow={Math.min(Math.ceil(chartData.length / 2), 2)}
517521
legendWidth={420}
518522
labelFontSize={14}
523+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.storage}
519524
tooltipLabelFormatter={({ datum, percent }) =>
520525
`${datum.countDisplay}\n${percent.toFixed(1)}%`
521526
}
@@ -611,6 +616,7 @@ export const StorageOverview: React.FC<StorageOverviewProps> = ({
611616
)}
612617
legendWidth={420}
613618
labelFontSize={14}
619+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.storage}
614620
tooltipLabelFormatter={({ datum, percent }) =>
615621
`${datum.countDisplay}\n${percent.toFixed(1)}%`
616622
}
@@ -635,6 +641,7 @@ export const StorageOverview: React.FC<StorageOverviewProps> = ({
635641
)}
636642
legendWidth={420}
637643
labelFontSize={14}
644+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.storage}
638645
tooltipLabelFormatter={({ datum, percent }) =>
639646
`${datum.countDisplay}\n${percent.toFixed(1)}%`
640647
}
@@ -656,6 +663,7 @@ export const StorageOverview: React.FC<StorageOverviewProps> = ({
656663
itemsPerRow={Math.ceil(sharedDisksChartData.length / 2)}
657664
labelFontSize={18}
658665
marginLeft="52%"
666+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.storage}
659667
tooltipLabelFormatter={({ datum, percent }) =>
660668
`${datum.countDisplay}\n${percent.toFixed(1)}%`
661669
}

src/ui/report/views/assessment-report/VMMigrationStatus.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import RhUiVirtualMachineIcon from "@patternfly/react-icons/dist/esm/icons/virtu
33
import React from "react";
44

55
import MigrationDonutChart from "../../../core/components/MigrationDonutChart";
6-
import { chartColorFailure, chartColorSuccess } from "./constants";
6+
import {
7+
chartColorFailure,
8+
chartColorSuccess,
9+
REPORT_CARD_EMPTY_STATE_TITLES,
10+
} from "./constants";
711
import { dashboardCard } from "./styles";
812

913
interface VmMigrationStatusProps {
@@ -65,6 +69,7 @@ export const VMMigrationStatus: React.FC<VmMigrationStatusProps> = ({
6569
labelFontSize={18}
6670
itemsPerRow={2}
6771
marginLeft="40%"
72+
emptyStateTitle={REPORT_CARD_EMPTY_STATE_TITLES.migrationStatus}
6873
/>
6974
</CardBody>
7075
</Card>

src/ui/report/views/assessment-report/constants.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,18 @@ import { chart_color_yellow_300 } from "@patternfly/react-tokens/dist/esm/chart_
88
*/
99
export const chartColorSuccess = chart_color_blue_300.value;
1010
export const chartColorFailure = chart_color_yellow_300.value;
11+
12+
export const REPORT_CARD_EMPTY_STATE_TITLES = {
13+
networks: "Network data not collected",
14+
nicCount: "NIC count data not collected",
15+
hosts: "Host data not collected",
16+
cpuMemory: "CPU and memory data not collected",
17+
cpu: "CPU data not collected",
18+
memory: "Memory data not collected",
19+
storage: "Storage data not collected",
20+
diskTypes: "Disk type data not collected",
21+
clusters: "Cluster data not collected",
22+
cpuOvercommitment: "CPU overcommitment data not collected",
23+
operatingSystems: "Operating system data not collected",
24+
migrationStatus: "Migration status data not collected",
25+
} as const;

0 commit comments

Comments
 (0)