@openshift-migration-advisor/shared-components 0.24.0 → 0.25.0-1701f64050d7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +31 -0
  2. package/dist/charts/index.d.ts +1 -1
  3. package/dist/charts/index.d.ts.map +1 -1
  4. package/dist/forms/RadioButtonFormGroup.d.ts.map +1 -1
  5. package/dist/forms/RadioButtonFormGroup.js +2 -2
  6. package/dist/report/ChartDownloadButton.d.ts +11 -0
  7. package/dist/report/ChartDownloadButton.d.ts.map +1 -0
  8. package/dist/report/ChartDownloadButton.js +24 -0
  9. package/dist/report/ChartExportProvider.d.ts +23 -0
  10. package/dist/report/ChartExportProvider.d.ts.map +1 -0
  11. package/dist/report/ChartExportProvider.js +222 -0
  12. package/dist/report/ChartExportSurface.d.ts +12 -0
  13. package/dist/report/ChartExportSurface.d.ts.map +1 -0
  14. package/dist/report/ChartExportSurface.js +32 -0
  15. package/dist/report/ErrorTable.d.ts +18 -0
  16. package/dist/report/ErrorTable.d.ts.map +1 -0
  17. package/dist/report/ErrorTable.js +20 -0
  18. package/dist/report/FeatureStatusBadge.d.ts +7 -0
  19. package/dist/report/FeatureStatusBadge.d.ts.map +1 -0
  20. package/dist/report/FeatureStatusBadge.js +13 -0
  21. package/dist/report/HostPowerStates.d.ts +8 -0
  22. package/dist/report/HostPowerStates.d.ts.map +1 -0
  23. package/dist/report/HostPowerStates.js +11 -0
  24. package/dist/report/HostsOverview.d.ts +13 -0
  25. package/dist/report/HostsOverview.d.ts.map +1 -0
  26. package/dist/report/HostsOverview.js +84 -0
  27. package/dist/report/InfrastructureSummary.d.ts +7 -0
  28. package/dist/report/InfrastructureSummary.d.ts.map +1 -0
  29. package/dist/report/InfrastructureSummary.js +9 -0
  30. package/dist/report/NetworkOverview.d.ts +31 -0
  31. package/dist/report/NetworkOverview.d.ts.map +1 -0
  32. package/dist/report/NetworkOverview.js +201 -0
  33. package/dist/report/OSDistribution.d.ts +0 -2
  34. package/dist/report/OSDistribution.d.ts.map +1 -1
  35. package/dist/report/OSDistribution.js +10 -15
  36. package/dist/report/OsSupportTiersHelpPopover.d.ts.map +1 -1
  37. package/dist/report/OsSupportTiersHelpPopover.js +2 -31
  38. package/dist/report/OsUpgradeNotice.d.ts.map +1 -1
  39. package/dist/report/OsUpgradeNotice.js +1 -5
  40. package/dist/report/OsUpgradeRecommendationPopover.d.ts +0 -1
  41. package/dist/report/OsUpgradeRecommendationPopover.d.ts.map +1 -1
  42. package/dist/report/OsUpgradeRecommendationPopover.js +4 -3
  43. package/dist/report/PowerStateCard.d.ts +16 -0
  44. package/dist/report/PowerStateCard.d.ts.map +1 -0
  45. package/dist/report/PowerStateCard.js +9 -0
  46. package/dist/report/ReportExportMenu.d.ts +19 -0
  47. package/dist/report/ReportExportMenu.d.ts.map +1 -0
  48. package/dist/report/ReportExportMenu.js +31 -0
  49. package/dist/report/ReportTable.d.ts +14 -0
  50. package/dist/report/ReportTable.d.ts.map +1 -0
  51. package/dist/report/ReportTable.js +23 -0
  52. package/dist/report/SupportTierBadge.d.ts +0 -1
  53. package/dist/report/SupportTierBadge.d.ts.map +1 -1
  54. package/dist/report/SupportTierBadge.js +1 -19
  55. package/dist/report/VCenterClusterDetails.d.ts +9 -0
  56. package/dist/report/VCenterClusterDetails.d.ts.map +1 -0
  57. package/dist/report/VCenterClusterDetails.js +31 -0
  58. package/dist/report/VmPowerStates.d.ts +8 -0
  59. package/dist/report/VmPowerStates.d.ts.map +1 -0
  60. package/dist/report/VmPowerStates.js +11 -0
  61. package/dist/report/WarningsTable.d.ts +9 -0
  62. package/dist/report/WarningsTable.d.ts.map +1 -0
  63. package/dist/report/WarningsTable.js +20 -0
  64. package/dist/report/captureChartElement.d.ts +8 -0
  65. package/dist/report/captureChartElement.d.ts.map +1 -0
  66. package/dist/report/captureChartElement.js +284 -0
  67. package/dist/report/chartExport.d.ts +73 -0
  68. package/dist/report/chartExport.d.ts.map +1 -0
  69. package/dist/report/chartExport.js +162 -0
  70. package/dist/report/chartExportContext.d.ts +32 -0
  71. package/dist/report/chartExportContext.d.ts.map +1 -0
  72. package/dist/report/chartExportContext.js +36 -0
  73. package/dist/report/chartExportFilenames.d.ts +4 -0
  74. package/dist/report/chartExportFilenames.d.ts.map +1 -0
  75. package/dist/report/chartExportFilenames.js +16 -0
  76. package/dist/report/constants.d.ts +4 -0
  77. package/dist/report/constants.d.ts.map +1 -1
  78. package/dist/report/constants.js +4 -0
  79. package/dist/report/dashboardStyles.d.ts +0 -4
  80. package/dist/report/dashboardStyles.d.ts.map +1 -1
  81. package/dist/report/dashboardStyles.js +0 -19
  82. package/dist/report/htmlExport.d.ts +9 -0
  83. package/dist/report/htmlExport.d.ts.map +1 -0
  84. package/dist/report/htmlExport.js +65 -0
  85. package/dist/report/index.d.ts +28 -0
  86. package/dist/report/index.d.ts.map +1 -1
  87. package/dist/report/index.js +26 -0
  88. package/dist/report/infrastructureSummaryModel.d.ts +82 -0
  89. package/dist/report/infrastructureSummaryModel.d.ts.map +1 -0
  90. package/dist/report/infrastructureSummaryModel.js +139 -0
  91. package/dist/report/pdfExport.d.ts +3 -0
  92. package/dist/report/pdfExport.d.ts.map +1 -0
  93. package/dist/report/pdfExport.js +131 -0
  94. package/dist/report/pdfPage.d.ts +15 -0
  95. package/dist/report/pdfPage.d.ts.map +1 -0
  96. package/dist/report/pdfPage.js +44 -0
  97. package/dist/report/powerStates.d.ts +11 -0
  98. package/dist/report/powerStates.d.ts.map +1 -0
  99. package/dist/report/powerStates.js +113 -0
  100. package/dist/report/reportExportOptions.d.ts +17 -0
  101. package/dist/report/reportExportOptions.d.ts.map +1 -0
  102. package/dist/report/reportExportOptions.js +31 -0
  103. package/dist/report/zipChartPngs.d.ts +3 -0
  104. package/dist/report/zipChartPngs.d.ts.map +1 -0
  105. package/dist/report/zipChartPngs.js +8 -0
  106. package/package.json +7 -2
  107. package/src/charts/index.ts +1 -0
  108. package/src/forms/RadioButtonFormGroup.tsx +10 -3
  109. package/src/report/ChartDownloadButton.tsx +59 -0
  110. package/src/report/ChartExportProvider.tsx +392 -0
  111. package/src/report/ChartExportSurface.tsx +60 -0
  112. package/src/report/ErrorTable.tsx +85 -0
  113. package/src/report/FeatureStatusBadge.tsx +30 -0
  114. package/src/report/HostPowerStates.tsx +38 -0
  115. package/src/report/HostsOverview.tsx +185 -0
  116. package/src/report/InfrastructureSummary.tsx +73 -0
  117. package/src/report/NetworkOverview.tsx +405 -0
  118. package/src/report/OSDistribution.tsx +96 -99
  119. package/src/report/OsSupportTiersHelpPopover.tsx +32 -62
  120. package/src/report/OsUpgradeNotice.tsx +1 -7
  121. package/src/report/OsUpgradeRecommendationPopover.tsx +3 -4
  122. package/src/report/PowerStateCard.tsx +86 -0
  123. package/src/report/ReportExportMenu.tsx +119 -0
  124. package/src/report/ReportTable.tsx +81 -0
  125. package/src/report/SupportTierBadge.tsx +12 -38
  126. package/src/report/VCenterClusterDetails.tsx +233 -0
  127. package/src/report/VmPowerStates.tsx +38 -0
  128. package/src/report/WarningsTable.tsx +75 -0
  129. package/src/report/__tests__/ChartExportProvider.test.tsx +542 -0
  130. package/src/report/__tests__/HostPowerStates.test.tsx +47 -0
  131. package/src/report/__tests__/HostsOverview.test.tsx +145 -0
  132. package/src/report/__tests__/InfrastructureSummary.test.tsx +126 -0
  133. package/src/report/__tests__/NetworkOverview.test.tsx +269 -0
  134. package/src/report/__tests__/OSDistribution.test.tsx +10 -11
  135. package/src/report/__tests__/captureChartElement.test.ts +132 -0
  136. package/src/report/__tests__/chartExportPackagers.test.ts +282 -0
  137. package/src/report/__tests__/infrastructureSummaryModel.test.ts +224 -0
  138. package/src/report/__tests__/powerStates.test.ts +70 -0
  139. package/src/report/captureChartElement.ts +368 -0
  140. package/src/report/chartExport.ts +255 -0
  141. package/src/report/chartExportContext.tsx +92 -0
  142. package/src/report/chartExportFilenames.ts +21 -0
  143. package/src/report/constants.ts +4 -0
  144. package/src/report/dashboardStyles.ts +0 -23
  145. package/src/report/htmlExport.ts +83 -0
  146. package/src/report/index.ts +154 -0
  147. package/src/report/infrastructureSummaryModel.ts +281 -0
  148. package/src/report/pdfExport.ts +233 -0
  149. package/src/report/pdfPage.ts +83 -0
  150. package/src/report/powerStates.ts +169 -0
  151. package/src/report/reportExportOptions.ts +53 -0
  152. package/src/report/zipChartPngs.ts +10 -0
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Card, CardBody, CardTitle, DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, Flex, FlexItem, } from "@patternfly/react-core";
3
+ import { ChartHeaderActions } from "./ChartDownloadButton.js";
4
+ import { ChartExportSurface } from "./ChartExportSurface.js";
5
+ const formatCount = (value) => typeof value === "number" ? String(value) : "—";
6
+ const INFRA_CHART_ID = "infrastructure-summary";
7
+ const INFRA_TITLE = "Infrastructure summary";
8
+ export const InfrastructureSummary = ({ summary, }) => (_jsx(ChartExportSurface, { id: INFRA_CHART_ID, title: INFRA_TITLE, children: _jsxs(Card, { isFullHeight: true, children: [_jsx(CardTitle, { children: _jsxs(Flex, { justifyContent: { default: "justifyContentSpaceBetween" }, alignItems: { default: "alignItemsCenter" }, children: [_jsx(FlexItem, { children: INFRA_TITLE }), _jsx(ChartHeaderActions, { chartId: INFRA_CHART_ID, title: INFRA_TITLE })] }) }), _jsx(CardBody, { children: _jsxs(DescriptionList, { isAutoFit: true, displaySize: "lg", children: [_jsxs(DescriptionListGroup, { children: [_jsx(DescriptionListTerm, { children: "VMware version" }), _jsx(DescriptionListDescription, { children: summary.vmwareVersion })] }), _jsxs(DescriptionListGroup, { children: [_jsx(DescriptionListTerm, { children: "Datacenters" }), _jsx(DescriptionListDescription, { children: formatCount(summary.datacenters) })] }), _jsxs(DescriptionListGroup, { children: [_jsx(DescriptionListTerm, { children: "vCenters" }), _jsx(DescriptionListDescription, { children: formatCount(summary.vCenters) })] }), _jsxs(DescriptionListGroup, { children: [_jsx(DescriptionListTerm, { children: "ESXi hosts" }), _jsx(DescriptionListDescription, { children: formatCount(summary.esxiHosts) })] })] }) })] }) }));
9
+ InfrastructureSummary.displayName = "InfrastructureSummary";
@@ -0,0 +1,31 @@
1
+ import type { FC } from "react";
2
+ import { type MigrationDonutChartLegendVariant } from "../charts/MigrationDonutChart.js";
3
+ /** Network fields this card reads. Apps pass SDK networks structurally. */
4
+ export interface NetworkLike {
5
+ vmsCount?: number;
6
+ vlanId?: string | number;
7
+ }
8
+ /** Infra fields this card reads. */
9
+ export interface NetworkInfraLike {
10
+ networks?: NetworkLike[];
11
+ }
12
+ /** Deprecated NIC histogram used when `distributionByNicCount` is absent. */
13
+ export interface NicCountHistogram {
14
+ data?: number[];
15
+ minValue?: number;
16
+ step?: number;
17
+ }
18
+ /** NIC summary fields this card reads from the VM resource breakdown. */
19
+ export interface NicCountSummary {
20
+ total?: number;
21
+ histogram?: NicCountHistogram;
22
+ }
23
+ export interface NetworkOverviewProps {
24
+ infra?: NetworkInfraLike;
25
+ nicCount?: NicCountSummary;
26
+ distributionByNicCount?: Record<string, number>;
27
+ /** `"html"` in agent-ui; ui-app passes `"chart"`. */
28
+ legendVariant?: MigrationDonutChartLegendVariant;
29
+ }
30
+ export declare const NetworkOverview: FC<NetworkOverviewProps>;
31
+ //# sourceMappingURL=NetworkOverview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NetworkOverview.d.ts","sourceRoot":"","sources":["../../src/report/NetworkOverview.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,EAAE,EAAO,MAAM,OAAO,CAAC;AAErC,OAAO,EAGL,KAAK,gCAAgC,EACtC,MAAM,kCAAkC,CAAC;AAQ1C,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED,oCAAoC;AACpC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;CAC1B;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,qDAAqD;IACrD,aAAa,CAAC,EAAE,gCAAgC,CAAC;CAClD;AAiND,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CA2HpD,CAAC"}
@@ -0,0 +1,201 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { css } from "@emotion/css";
3
+ import { Card, CardBody, CardTitle, Dropdown, DropdownItem, DropdownList, Flex, FlexItem, MenuToggle, } from "@patternfly/react-core";
4
+ import { TopologyIcon } from "@patternfly/react-icons";
5
+ import { chart_color_black_500, chart_color_blue_300, chart_color_green_300, chart_color_orange_100, chart_color_purple_100, chart_color_purple_300, chart_color_red_orange_200, chart_color_teal_200, chart_color_teal_400, chart_color_yellow_400, } from "@patternfly/react-tokens";
6
+ import { useMemo, useState } from "react";
7
+ import { MigrationDonutChart, } from "../charts/MigrationDonutChart.js";
8
+ import { CardEmptyState } from "./CardEmptyState.js";
9
+ import { ChartHeaderActions } from "./ChartDownloadButton.js";
10
+ import { ChartExportSurface } from "./ChartExportSurface.js";
11
+ import { chartExportViewsFromLabels } from "./chartExport.js";
12
+ import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants.js";
13
+ import { dashboardStyles } from "./dashboardStyles.js";
14
+ const VIEW_MODE_LABELS = {
15
+ networkDistribution: "VM distribution by network",
16
+ nicCount: "VM distribution by NIC count",
17
+ };
18
+ const TOP_NETWORKS = 4;
19
+ const REST_OF_NETWORKS_LABEL = "Rest of networks";
20
+ const CHART_ID = "network-overview";
21
+ const CHART_TITLE = "Networks";
22
+ /**
23
+ * Categorical order from the ui-app network donut, mapped onto PatternFly
24
+ * `chart_color_*` tokens (nearest token where the old hex was not a token).
25
+ */
26
+ const NETWORK_COLORS = [
27
+ chart_color_blue_300.value,
28
+ chart_color_purple_300.value,
29
+ chart_color_purple_100.value,
30
+ chart_color_teal_200.value,
31
+ chart_color_yellow_400.value,
32
+ chart_color_green_300.value,
33
+ chart_color_orange_100.value,
34
+ chart_color_red_orange_200.value,
35
+ chart_color_teal_400.value,
36
+ chart_color_black_500.value,
37
+ ];
38
+ const cardSubtitle = css `
39
+ color: var(--pf-t--global--text--color--subtle);
40
+ font-size: 0.85rem;
41
+ `;
42
+ const menuToggleMinWidth = css `
43
+ min-width: 250px;
44
+ `;
45
+ const titleRow = css `
46
+ width: 100%;
47
+ `;
48
+ const isViewMode = (value) => value === "networkDistribution" || value === "nicCount";
49
+ const legendFor = (categories) => {
50
+ const legend = {};
51
+ categories.forEach((category, index) => {
52
+ const color = NETWORK_COLORS[index % NETWORK_COLORS.length];
53
+ if (color) {
54
+ legend[category] = color;
55
+ }
56
+ });
57
+ return legend;
58
+ };
59
+ const vlanLabel = (vlanId) => {
60
+ if (typeof vlanId !== "string" && typeof vlanId !== "number") {
61
+ return "-";
62
+ }
63
+ const value = String(vlanId).trim();
64
+ return value !== "" ? value : "-";
65
+ };
66
+ const buildNetworkDonut = (networks) => {
67
+ const items = (Array.isArray(networks) ? networks : [])
68
+ .map((network) => ({
69
+ vmsCount: typeof network?.vmsCount === "number" ? network.vmsCount : Number.NaN,
70
+ vlanId: vlanLabel(network?.vlanId),
71
+ }))
72
+ .filter((network) => Number.isFinite(network.vmsCount) && network.vmsCount >= 0)
73
+ .sort((a, b) => b.vmsCount - a.vmsCount);
74
+ const totalVMs = items.reduce((sum, network) => sum + network.vmsCount, 0);
75
+ const top = items.slice(0, TOP_NETWORKS);
76
+ const restSum = items
77
+ .slice(TOP_NETWORKS)
78
+ .reduce((sum, network) => sum + network.vmsCount, 0);
79
+ const vlanBySlice = {};
80
+ const slices = top.map((network, index) => {
81
+ const name = `Network ${index + 1}`;
82
+ vlanBySlice[name] = network.vlanId;
83
+ return {
84
+ name,
85
+ count: network.vmsCount,
86
+ countDisplay: `${network.vmsCount} VMs`,
87
+ legendCategory: name,
88
+ };
89
+ });
90
+ if (restSum > 0) {
91
+ slices.push({
92
+ name: REST_OF_NETWORKS_LABEL,
93
+ count: restSum,
94
+ countDisplay: `${restSum} VMs`,
95
+ legendCategory: REST_OF_NETWORKS_LABEL,
96
+ });
97
+ vlanBySlice[REST_OF_NETWORKS_LABEL] = "-";
98
+ }
99
+ return {
100
+ slices,
101
+ legend: legendFor(slices.map((slice) => slice.legendCategory)),
102
+ title: `${totalVMs}`,
103
+ vlanBySlice,
104
+ };
105
+ };
106
+ const nicBucketLabel = (bucket) => {
107
+ const count = Number.parseInt(bucket, 10);
108
+ if (bucket.endsWith("+")) {
109
+ return `${count}+ NIC`;
110
+ }
111
+ return count === 1 ? "1 NIC" : `${count} NIC`;
112
+ };
113
+ const compareNicBuckets = (a, b) => {
114
+ const aPlus = a.bucket.endsWith("+");
115
+ const bPlus = b.bucket.endsWith("+");
116
+ if (aPlus !== bPlus) {
117
+ return aPlus ? 1 : -1;
118
+ }
119
+ const aNum = Number.parseInt(a.bucket, 10);
120
+ const bNum = Number.parseInt(b.bucket, 10);
121
+ if (Number.isFinite(aNum) && Number.isFinite(bNum)) {
122
+ return aNum - bNum;
123
+ }
124
+ return a.bucket.localeCompare(b.bucket);
125
+ };
126
+ const slicesFromBuckets = (entries) => entries.map((entry) => {
127
+ const label = nicBucketLabel(entry.bucket);
128
+ return {
129
+ name: label,
130
+ count: entry.count,
131
+ countDisplay: `${entry.count} VMs`,
132
+ legendCategory: label,
133
+ };
134
+ });
135
+ const buildNicDonut = (distributionByNicCount, nicCount) => {
136
+ if (distributionByNicCount != null) {
137
+ const entries = Object.entries(distributionByNicCount)
138
+ .map(([bucket, value]) => ({
139
+ bucket,
140
+ count: Number.isFinite(Number(value)) ? Number(value) : 0,
141
+ }))
142
+ .filter((entry) => entry.count > 0)
143
+ .sort(compareNicBuckets);
144
+ const slices = slicesFromBuckets(entries);
145
+ const total = entries.reduce((sum, entry) => sum + entry.count, 0);
146
+ return {
147
+ slices,
148
+ legend: legendFor(slices.map((slice) => slice.legendCategory)),
149
+ title: `${total}`,
150
+ };
151
+ }
152
+ const histogram = nicCount?.histogram;
153
+ const data = Array.isArray(histogram?.data) ? histogram.data : [];
154
+ const minValue = typeof histogram?.minValue === "number" ? histogram.minValue : 0;
155
+ const step = typeof histogram?.step === "number" ? histogram.step : 1;
156
+ const buckets = data
157
+ .map((count, index) => ({
158
+ bucket: String(minValue + index * step),
159
+ count: Number(count) || 0,
160
+ }))
161
+ .filter((entry) => entry.count > 0)
162
+ .sort((a, b) => Number(a.bucket) - Number(b.bucket));
163
+ const slices = slicesFromBuckets(buckets);
164
+ const total = typeof nicCount?.total === "number"
165
+ ? nicCount.total
166
+ : buckets.reduce((sum, entry) => sum + entry.count, 0);
167
+ return {
168
+ slices,
169
+ legend: legendFor(slices.map((slice) => slice.legendCategory)),
170
+ title: `${total}`,
171
+ };
172
+ };
173
+ export const NetworkOverview = ({ infra, nicCount, distributionByNicCount, legendVariant = "html", }) => {
174
+ const [viewMode, setViewMode] = useState("networkDistribution");
175
+ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
176
+ const networkChart = useMemo(() => buildNetworkDonut(infra?.networks), [infra?.networks]);
177
+ const nicChart = useMemo(() => buildNicDonut(distributionByNicCount, nicCount), [distributionByNicCount, nicCount]);
178
+ const chartTitle = `${CHART_TITLE} — ${VIEW_MODE_LABELS[viewMode]}`;
179
+ const activeChart = viewMode === "networkDistribution" ? networkChart : nicChart;
180
+ const emptyTitle = viewMode === "networkDistribution"
181
+ ? REPORT_CARD_EMPTY_STATE_TITLES.networks
182
+ : REPORT_CARD_EMPTY_STATE_TITLES.nicCount;
183
+ return (_jsx(ChartExportSurface, { id: CHART_ID, title: chartTitle, exportViews: chartExportViewsFromLabels(CHART_TITLE, VIEW_MODE_LABELS), activeExportViewId: viewMode, onExportViewChange: (viewId) => {
184
+ if (isViewMode(viewId)) {
185
+ setViewMode(viewId);
186
+ }
187
+ }, children: _jsxs(Card, { className: dashboardStyles.card, children: [_jsx(CardTitle, { children: _jsxs(Flex, { className: titleRow, justifyContent: { default: "justifyContentSpaceBetween" }, alignItems: { default: "alignItemsCenter" }, children: [_jsx(FlexItem, { children: _jsxs("div", { children: [_jsxs("div", { children: [_jsx(TopologyIcon, {}), " ", CHART_TITLE] }), viewMode === "networkDistribution" && (_jsx("div", { className: cardSubtitle, children: "Top 5 networks" }))] }) }), _jsx(ChartHeaderActions, { chartId: CHART_ID, title: chartTitle, children: _jsx(Dropdown, { isOpen: isDropdownOpen, onSelect: (_event, value) => {
188
+ if (isViewMode(value)) {
189
+ setViewMode(value);
190
+ }
191
+ setIsDropdownOpen(false);
192
+ }, onOpenChange: setIsDropdownOpen, toggle: (toggleRef) => (_jsx(MenuToggle, { ref: toggleRef, onClick: () => setIsDropdownOpen((open) => !open), isExpanded: isDropdownOpen, className: menuToggleMinWidth, children: VIEW_MODE_LABELS[viewMode] })), children: _jsxs(DropdownList, { children: [_jsx(DropdownItem, { value: "networkDistribution", children: VIEW_MODE_LABELS.networkDistribution }, "networkDistribution"), _jsx(DropdownItem, { value: "nicCount", children: VIEW_MODE_LABELS.nicCount }, "nicCount")] }) }) })] }) }), _jsx(CardBody, { className: dashboardStyles.cardBodyScrollable, children: activeChart.slices.length === 0 ? (_jsx(CardEmptyState, { title: emptyTitle })) : (_jsx(MigrationDonutChart, { legendVariant: legendVariant, data: activeChart.slices, legend: activeChart.legend, height: 300, width: 420, donutThickness: 18, titleFontSize: 34, title: activeChart.title, subTitle: "VMs", subTitleColor: "var(--pf-t--global--text--color--subtle)", itemsPerRow: Math.ceil(activeChart.slices.length / 2), labelFontSize: 18, marginLeft: "0%", tooltipLabelFormatter: ({ datum, percent }) => {
193
+ const summary = `${datum.countDisplay}\n${percent.toFixed(1)}%`;
194
+ if (viewMode !== "networkDistribution") {
195
+ return summary;
196
+ }
197
+ const vlan = networkChart.vlanBySlice[datum.legendCategory];
198
+ return `${summary}\nVLAN: ${vlan ?? "-"}`;
199
+ } })) })] }) }));
200
+ };
201
+ NetworkOverview.displayName = "NetworkOverview";
@@ -2,12 +2,10 @@ import type { FC } from "react";
2
2
  import { type OSDistributionEntry } from "./osSupportTier.js";
3
3
  interface OSDistributionProps {
4
4
  osData: Record<string, OSDistributionEntry>;
5
- isExportMode?: boolean;
6
5
  }
7
6
  export declare const OSDistribution: FC<OSDistributionProps>;
8
7
  interface OSBarChartProps {
9
8
  osData: Record<string, OSDistributionEntry>;
10
- isExportMode?: boolean;
11
9
  }
12
10
  export declare const OSBarChart: FC<OSBarChartProps>;
13
11
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"OSDistribution.d.ts","sourceRoot":"","sources":["../../src/report/OSDistribution.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,EAAE,EAAO,MAAM,OAAO,CAAC;AAQrC,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAyB5B,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAyBlD,CAAC;AAEF,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAgH1C,CAAC"}
1
+ {"version":3,"file":"OSDistribution.d.ts","sourceRoot":"","sources":["../../src/report/OSDistribution.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,EAAE,EAAO,MAAM,OAAO,CAAC;AAWrC,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAe5B,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAC7C;AAED,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAmClD,CAAC;AAEF,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAC7C;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA0G1C,CAAC"}
@@ -1,9 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { css } from "@emotion/css";
3
- import { Card, CardBody, CardTitle, Flex, FlexItem, MenuToggle, SearchInput, Select, SelectList, SelectOption, Toolbar, ToolbarContent, ToolbarItem, } from "@patternfly/react-core";
3
+ import { Card, CardBody, CardTitle, Flex, FlexItem, MenuToggle, SearchInput, Select, SelectList, SelectOption, Stack, StackItem, Toolbar, ToolbarContent, ToolbarItem, } from "@patternfly/react-core";
4
4
  import { DesktopIcon } from "@patternfly/react-icons";
5
5
  import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
6
6
  import { CardEmptyState } from "./CardEmptyState.js";
7
+ import { ChartHeaderActions } from "./ChartDownloadButton.js";
8
+ import { ChartExportSurface } from "./ChartExportSurface.js";
9
+ import { chartExportHideProps, chartExportScrollProps } from "./chartExport.js";
7
10
  import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants.js";
8
11
  import { dashboardStyles, tableFullWidthStyle } from "./dashboardStyles.js";
9
12
  import { EmptySearchResults } from "./EmptySearchResults.js";
@@ -13,25 +16,17 @@ import { OsNameCell } from "./OsUpgradeRecommendationPopover.js";
13
16
  import { getSupportTierLegendLabel, ORDERED_SUPPORT_TIERS, } from "./osSupportTier.js";
14
17
  import { SupportTierBadge } from "./SupportTierBadge.js";
15
18
  import { ALL_TIERS_FILTER, useOsBarChartViewModel, } from "./useOsBarChartViewModel.js";
16
- const filterToolbarStyle = css `
17
- padding-left: 0;
18
- padding-right: 0;
19
- `;
20
- const filterItemStyle = css `
21
- flex: 1 1 0;
22
- min-width: 0;
23
- `;
24
- const vmsColumnStyle = css `
25
- text-align: right;
26
- `;
27
19
  const tableScrollStyle = css `
28
20
  overflow: auto;
21
+ max-height: 350px;
29
22
  `;
30
- export const OSDistribution = ({ osData, isExportMode = false, }) => (_jsxs(Card, { className: isExportMode ? dashboardStyles.cardPrint : dashboardStyles.card, id: "os-distribution", children: [_jsx(CardTitle, { children: _jsxs(Flex, { alignItems: { default: "alignItemsCenter" }, spaceItems: { default: "spaceItemsSm" }, children: [_jsxs(FlexItem, { children: [_jsx(DesktopIcon, {}), " Operating Systems"] }), _jsx(FlexItem, { children: _jsx(OsSupportTiersHelpPopover, {}) })] }) }), _jsx(CardBody, { children: _jsx(OSBarChart, { osData: osData, isExportMode: isExportMode }) })] }));
31
- export const OSBarChart = ({ osData, isExportMode = false, }) => {
23
+ const OS_DISTRIBUTION_CHART_ID = "os-distribution";
24
+ const OS_DISTRIBUTION_TITLE = "Operating system distribution";
25
+ export const OSDistribution = ({ osData }) => (_jsx(ChartExportSurface, { id: OS_DISTRIBUTION_CHART_ID, title: OS_DISTRIBUTION_TITLE, children: _jsxs(Card, { className: dashboardStyles.card, children: [_jsx(CardTitle, { children: _jsxs(Flex, { justifyContent: { default: "justifyContentSpaceBetween" }, alignItems: { default: "alignItemsCenter" }, children: [_jsx(FlexItem, { children: _jsxs(Flex, { alignItems: { default: "alignItemsCenter" }, spaceItems: { default: "spaceItemsSm" }, children: [_jsxs(FlexItem, { children: [_jsx(DesktopIcon, {}), " Operating Systems"] }), _jsx(FlexItem, { ...chartExportHideProps, children: _jsx(OsSupportTiersHelpPopover, {}) })] }) }), _jsx(ChartHeaderActions, { chartId: OS_DISTRIBUTION_CHART_ID, title: OS_DISTRIBUTION_TITLE })] }) }), _jsx(CardBody, { children: _jsx(OSBarChart, { osData: osData }) })] }) }));
26
+ export const OSBarChart = ({ osData }) => {
32
27
  const vm = useOsBarChartViewModel(osData);
33
28
  if (vm.tableRows.length === 0) {
34
29
  return (_jsx(CardEmptyState, { title: REPORT_CARD_EMPTY_STATE_TITLES.operatingSystems }));
35
30
  }
36
- return (_jsxs(_Fragment, { children: [!isExportMode ? (_jsx(Toolbar, { className: filterToolbarStyle, children: _jsxs(ToolbarContent, { children: [_jsx(ToolbarItem, { className: filterItemStyle, children: _jsx(SearchInput, { placeholder: "Filter by OS", value: vm.osFilter, onChange: (_event, value) => vm.setOsFilter(value), onClear: vm.clearOsFilter, "aria-label": "Filter operating systems by name" }) }), _jsx(ToolbarItem, { className: filterItemStyle, children: _jsx(Select, { isOpen: vm.isTierSelectOpen, selected: vm.tierFilter, onSelect: vm.handleTierSelect, onOpenChange: vm.setIsTierSelectOpen, toggle: (toggleRef) => (_jsx(MenuToggle, { ref: toggleRef, isExpanded: vm.isTierSelectOpen, onClick: vm.toggleTierSelectOpen, style: { width: "100%" }, children: vm.tierFilterLabel })), "aria-label": "Filter operating systems by support tier", children: _jsxs(SelectList, { children: [_jsx(SelectOption, { value: ALL_TIERS_FILTER, children: "All tiers" }), ORDERED_SUPPORT_TIERS.map((tier) => (_jsx(SelectOption, { value: tier, children: getSupportTierLegendLabel(tier) }, tier)))] }) }) })] }) })) : null, vm.showUpgradeNotice ? _jsx(OsUpgradeNotice, {}) : null, _jsx("div", { className: isExportMode ? undefined : tableScrollStyle, style: isExportMode ? undefined : { maxHeight: "350px" }, children: _jsxs(Table, { "aria-label": "Operating systems", variant: "compact", className: tableFullWidthStyle, children: [_jsx(Thead, { children: _jsxs(Tr, { children: [_jsx(Th, { children: "OS" }), _jsx(Th, { children: "Tier" }), _jsx(Th, { className: vmsColumnStyle, children: "VMs" })] }) }), _jsx(Tbody, { children: vm.showNoResults ? (_jsx(Tr, { children: _jsx(Td, { colSpan: 3, children: _jsx(EmptySearchResults, { title: "No matching operating system found" }) }) })) : (vm.filteredRows.map((row) => (_jsxs(Tr, { children: [_jsx(Td, { dataLabel: "OS", children: _jsx(OsNameCell, { osName: row.osName, upgradeRecommendation: row.upgradeRecommendation, isExportMode: isExportMode }) }), _jsx(Td, { dataLabel: "Tier", children: _jsx(SupportTierBadge, { tier: row.tier, isExportMode: isExportMode }) }), _jsx(Td, { dataLabel: "VMs", className: vmsColumnStyle, children: row.count })] }, row.osName)))) })] }) })] }));
31
+ return (_jsxs(_Fragment, { children: [_jsx("div", { ...chartExportHideProps, children: _jsx(Toolbar, { hasNoPadding: true, children: _jsxs(ToolbarContent, { children: [_jsx(ToolbarItem, { children: _jsx(SearchInput, { placeholder: "Filter by OS", value: vm.osFilter, onChange: (_event, value) => vm.setOsFilter(value), onClear: vm.clearOsFilter, "aria-label": "Filter operating systems by name" }) }), _jsx(ToolbarItem, { children: _jsx(Select, { isOpen: vm.isTierSelectOpen, selected: vm.tierFilter, onSelect: vm.handleTierSelect, onOpenChange: vm.setIsTierSelectOpen, toggle: (toggleRef) => (_jsx(MenuToggle, { ref: toggleRef, isExpanded: vm.isTierSelectOpen, onClick: vm.toggleTierSelectOpen, isFullWidth: true, children: vm.tierFilterLabel })), "aria-label": "Filter operating systems by support tier", children: _jsxs(SelectList, { children: [_jsx(SelectOption, { value: ALL_TIERS_FILTER, children: "All tiers" }), ORDERED_SUPPORT_TIERS.map((tier) => (_jsx(SelectOption, { value: tier, children: getSupportTierLegendLabel(tier) }, tier)))] }) }) })] }) }) }), _jsxs(Stack, { hasGutter: true, children: [vm.showUpgradeNotice ? (_jsx(StackItem, { children: _jsx(OsUpgradeNotice, {}) })) : null, _jsx(StackItem, { children: _jsx("div", { className: `${tableScrollStyle} ${tableFullWidthStyle}`, ...chartExportScrollProps, children: _jsxs(Table, { "aria-label": "Operating systems", variant: "compact", children: [_jsx(Thead, { children: _jsxs(Tr, { children: [_jsx(Th, { children: "OS" }), _jsx(Th, { children: "Tier" }), _jsx(Th, { children: "VMs" })] }) }), _jsx(Tbody, { children: vm.showNoResults ? (_jsx(Tr, { children: _jsx(Td, { colSpan: 3, children: _jsx(EmptySearchResults, { title: "No matching operating system found" }) }) })) : (vm.filteredRows.map((row) => (_jsxs(Tr, { children: [_jsx(Td, { dataLabel: "OS", children: _jsx(OsNameCell, { osName: row.osName, upgradeRecommendation: row.upgradeRecommendation }) }), _jsx(Td, { dataLabel: "Tier", children: _jsx(SupportTierBadge, { tier: row.tier }) }), _jsx(Td, { dataLabel: "VMs", children: row.count })] }, row.osName)))) })] }) }) })] })] }));
37
32
  };
@@ -1 +1 @@
1
- {"version":3,"file":"OsSupportTiersHelpPopover.d.ts","sourceRoot":"","sources":["../../src/report/OsSupportTiersHelpPopover.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAyEhC,eAAO,MAAM,yBAAyB,EAAE,EASvC,CAAC"}
1
+ {"version":3,"file":"OsSupportTiersHelpPopover.d.ts","sourceRoot":"","sources":["../../src/report/OsSupportTiersHelpPopover.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAsChC,eAAO,MAAM,yBAAyB,EAAE,EASvC,CAAC"}
@@ -1,37 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { css } from "@emotion/css";
3
- import { Label } from "@patternfly/react-core";
2
+ import { Button, Content, Label, Stack, StackItem, } from "@patternfly/react-core";
4
3
  import { ExternalLinkAltIcon } from "@patternfly/react-icons";
5
4
  import { getSupportTierBadgeColor, getSupportTierDefinition, getSupportTierLegendLabel, ORDERED_SUPPORT_TIERS, SUPPORT_TIER_LEARN_MORE_URL, } from "./osSupportTier.js";
6
5
  import PopoverIcon from "./PopoverIcon.js";
7
- const tierListStyle = css `
8
- list-style: none;
9
- padding: 0;
10
- margin: 0;
11
- display: flex;
12
- flex-direction: column;
13
- gap: var(--pf-t--global--spacer--400);
14
- `;
15
- const tierItemStyle = css `
16
- display: flex;
17
- flex-direction: column;
18
- gap: var(--pf-t--global--spacer--100);
19
- `;
20
- const tierBadgeStyle = css `
21
- width: fit-content;
22
- max-width: 100%;
23
- align-self: flex-start;
24
- `;
25
- const tierDescriptionStyle = css `
26
- margin: 0;
27
- color: var(--pf-t--global--text--color--regular);
28
- `;
29
- const learnMoreLinkStyle = css `
30
- display: inline-flex;
31
- align-items: center;
32
- gap: var(--pf-t--global--spacer--xs);
33
- margin-top: var(--pf-t--global--spacer--400);
34
- `;
35
- const OsSupportTiersHelpBody = () => (_jsxs("div", { children: [_jsx("ul", { className: tierListStyle, children: ORDERED_SUPPORT_TIERS.map((tier) => (_jsxs("li", { className: tierItemStyle, children: [_jsx(Label, { className: tierBadgeStyle, color: getSupportTierBadgeColor(tier), isCompact: true, children: getSupportTierLegendLabel(tier) }), _jsx("p", { className: tierDescriptionStyle, children: getSupportTierDefinition(tier) })] }, tier))) }), _jsxs("a", { "aria-label": "Learn more about operating system support tiers", className: learnMoreLinkStyle, href: SUPPORT_TIER_LEARN_MORE_URL, target: "_blank", rel: "noopener noreferrer", children: ["Learn more ", _jsx(ExternalLinkAltIcon, {})] })] }));
6
+ const OsSupportTiersHelpBody = () => (_jsxs(Stack, { hasGutter: true, children: [ORDERED_SUPPORT_TIERS.map((tier) => (_jsxs(StackItem, { children: [_jsx(Label, { color: getSupportTierBadgeColor(tier), isCompact: true, children: getSupportTierLegendLabel(tier) }), _jsx(Content, { component: "p", children: getSupportTierDefinition(tier) })] }, tier))), _jsx(StackItem, { children: _jsx(Button, { variant: "link", isInline: true, component: "a", href: SUPPORT_TIER_LEARN_MORE_URL, target: "_blank", rel: "noopener noreferrer", icon: _jsx(ExternalLinkAltIcon, {}), iconPosition: "end", "aria-label": "Learn more about operating system support tiers", children: "Learn more" }) })] }));
36
7
  export const OsSupportTiersHelpPopover = () => (_jsx(PopoverIcon, { noVerticalAlign: true, maxWidth: "40rem", headerContent: "Guest OS support tiers", bodyContent: _jsx(OsSupportTiersHelpBody, {}), buttonOuiaId: "guest-os-support-tiers-help", "aria-label": "Guest OS support tiers help" }));
37
8
  OsSupportTiersHelpPopover.displayName = "OsSupportTiersHelpPopover";
@@ -1 +1 @@
1
- {"version":3,"file":"OsUpgradeNotice.d.ts","sourceRoot":"","sources":["../../src/report/OsUpgradeNotice.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAMhC,eAAO,MAAM,eAAe,EAAE,EAiB7B,CAAC"}
1
+ {"version":3,"file":"OsUpgradeNotice.d.ts","sourceRoot":"","sources":["../../src/report/OsUpgradeNotice.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,eAAO,MAAM,eAAe,EAAE,EAgB7B,CAAC"}
@@ -1,9 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { css } from "@emotion/css";
3
2
  import { Content, Flex, FlexItem, Icon } from "@patternfly/react-core";
4
3
  import { InfoCircleIcon } from "@patternfly/react-icons";
5
- const noticeStyle = css `
6
- margin-bottom: var(--pf-t--global--spacer--200);
7
- `;
8
- export const OsUpgradeNotice = () => (_jsxs(Flex, { alignItems: { default: "alignItemsCenter" }, spaceItems: { default: "spaceItemsSm" }, className: noticeStyle, children: [_jsx(FlexItem, { children: _jsx(Icon, { status: "info", children: _jsx(InfoCircleIcon, {}) }) }), _jsx(FlexItem, { children: _jsx(Content, { component: "p", style: { fontWeight: 500 }, children: "Some operating systems may need upgrades before migration" }) })] }));
4
+ export const OsUpgradeNotice = () => (_jsxs(Flex, { alignItems: { default: "alignItemsCenter" }, spaceItems: { default: "spaceItemsSm" }, children: [_jsx(FlexItem, { children: _jsx(Icon, { status: "info", children: _jsx(InfoCircleIcon, {}) }) }), _jsx(FlexItem, { children: _jsx(Content, { component: "p", children: "Some operating systems may need upgrades before migration" }) })] }));
9
5
  OsUpgradeNotice.displayName = "OsUpgradeNotice";
@@ -6,7 +6,6 @@ export declare const OsUpgradeRecommendationPopover: FC<OsUpgradeRecommendationP
6
6
  interface OsNameCellProps {
7
7
  osName: string;
8
8
  upgradeRecommendation?: string;
9
- isExportMode?: boolean;
10
9
  }
11
10
  export declare const OsNameCell: FC<OsNameCellProps>;
12
11
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"OsUpgradeRecommendationPopover.d.ts","sourceRoot":"","sources":["../../src/report/OsUpgradeRecommendationPopover.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAchC,UAAU,mCAAmC;IAC3C,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,8BAA8B,EAAE,EAAE,CAC7C,mCAAmC,CAiBpC,CAAC;AAIF,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA0B1C,CAAC"}
1
+ {"version":3,"file":"OsUpgradeRecommendationPopover.d.ts","sourceRoot":"","sources":["../../src/report/OsUpgradeRecommendationPopover.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAehC,UAAU,mCAAmC;IAC3C,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,8BAA8B,EAAE,EAAE,CAC7C,mCAAmC,CAiBpC,CAAC;AAIF,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAyB1C,CAAC"}
@@ -2,6 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import { css } from "@emotion/css";
3
3
  import { Button, Flex, FlexItem, Popover } from "@patternfly/react-core";
4
4
  import { InfoCircleIcon } from "@patternfly/react-icons";
5
+ import { chartExportHideProps } from "./chartExport.js";
5
6
  const upgradeRecommendationPopoverCloseButton = css `
6
7
  .pf-v6-c-popover__close .pf-v6-c-button.pf-m-plain,
7
8
  .pf-v6-c-popover__close .pf-v6-c-button.pf-m-plain:hover {
@@ -14,11 +15,11 @@ const infoButtonStyle = css `
14
15
  `;
15
16
  export const OsUpgradeRecommendationPopover = ({ upgradeRecommendation }) => (_jsx(Popover, { className: upgradeRecommendationPopoverCloseButton, position: "bottom", headerContent: "Upgrade to get support", bodyContent: _jsx("div", { children: upgradeRecommendation }), children: _jsx(Button, { type: "button", "aria-label": "Open operating system upgrade information", variant: "plain", className: infoButtonStyle, children: _jsx(InfoCircleIcon, { color: "var(--pf-t--global--icon--color--status--info--default)" }) }) }));
16
17
  OsUpgradeRecommendationPopover.displayName = "OsUpgradeRecommendationPopover";
17
- export const OsNameCell = ({ osName, upgradeRecommendation, isExportMode = false, }) => {
18
+ export const OsNameCell = ({ osName, upgradeRecommendation, }) => {
18
19
  const hasUpgradeRecommendation = upgradeRecommendation && upgradeRecommendation.trim() !== "";
19
- if (!hasUpgradeRecommendation || isExportMode) {
20
+ if (!hasUpgradeRecommendation) {
20
21
  return _jsx(_Fragment, { children: osName });
21
22
  }
22
- return (_jsxs(Flex, { alignItems: { default: "alignItemsCenter" }, spaceItems: { default: "spaceItemsXs" }, flexWrap: { default: "nowrap" }, children: [_jsx(FlexItem, { children: osName }), _jsx(FlexItem, { shrink: { default: "shrink" }, children: _jsx(OsUpgradeRecommendationPopover, { upgradeRecommendation: upgradeRecommendation }) })] }));
23
+ return (_jsxs(Flex, { alignItems: { default: "alignItemsCenter" }, spaceItems: { default: "spaceItemsXs" }, flexWrap: { default: "nowrap" }, children: [_jsx(FlexItem, { children: osName }), _jsx(FlexItem, { shrink: { default: "shrink" }, ...chartExportHideProps, children: _jsx(OsUpgradeRecommendationPopover, { upgradeRecommendation: upgradeRecommendation }) })] }));
23
24
  };
24
25
  OsNameCell.displayName = "OsNameCell";
@@ -0,0 +1,16 @@
1
+ import type { FC, ReactNode } from "react";
2
+ import { type MigrationDonutChartDatum, type MigrationDonutChartLegendVariant } from "../charts/MigrationDonutChart.js";
3
+ export interface PowerStateCardProps {
4
+ id: string;
5
+ title: string;
6
+ icon: ReactNode;
7
+ emptyTitle: string;
8
+ slices: MigrationDonutChartDatum[];
9
+ legend: Record<string, string>;
10
+ total: number;
11
+ subTitle: string;
12
+ itemsPerRow?: number;
13
+ legendVariant?: MigrationDonutChartLegendVariant;
14
+ }
15
+ export declare const PowerStateCard: FC<PowerStateCardProps>;
16
+ //# sourceMappingURL=PowerStateCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PowerStateCard.d.ts","sourceRoot":"","sources":["../../src/report/PowerStateCard.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,gCAAgC,EACtC,MAAM,kCAAkC,CAAC;AAM1C,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,wBAAwB,EAAE,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,gCAAgC,CAAC;CAClD;AAED,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAoDlD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Card, CardBody, CardTitle, Flex, FlexItem, } from "@patternfly/react-core";
3
+ import { MigrationDonutChart, } from "../charts/MigrationDonutChart.js";
4
+ import { CardEmptyState } from "./CardEmptyState.js";
5
+ import { ChartHeaderActions } from "./ChartDownloadButton.js";
6
+ import { ChartExportSurface } from "./ChartExportSurface.js";
7
+ import { dashboardStyles } from "./dashboardStyles.js";
8
+ export const PowerStateCard = ({ id, title, icon, emptyTitle, slices, legend, total, subTitle, itemsPerRow = 2, legendVariant = "html", }) => (_jsx(ChartExportSurface, { id: id, title: title, children: _jsxs(Card, { className: dashboardStyles.card, children: [_jsx(CardTitle, { children: _jsxs(Flex, { justifyContent: { default: "justifyContentSpaceBetween" }, alignItems: { default: "alignItemsCenter" }, children: [_jsxs(FlexItem, { children: [icon, " ", title] }), _jsx(ChartHeaderActions, { chartId: id, title: title })] }) }), _jsx(CardBody, { children: total === 0 ? (_jsx(CardEmptyState, { title: emptyTitle })) : (_jsx(MigrationDonutChart, { legendVariant: legendVariant, data: slices, legend: legend, height: 300, width: 420, donutThickness: 18, padAngle: 1, title: `${total}`, subTitle: subTitle, subTitleColor: "var(--pf-t--global--text--color--subtle)", titleFontSize: 34, labelFontSize: 16, itemsPerRow: itemsPerRow, marginLeft: "0%", tooltipLabelFormatter: ({ datum, percent }) => `${datum.countDisplay}\n${percent.toFixed(1)}%` })) })] }) }));
9
+ PowerStateCard.displayName = "PowerStateCard";
@@ -0,0 +1,19 @@
1
+ import { type FC } from "react";
2
+ import { type ReportExportOption, type StandardReportExportHandlers } from "./reportExportOptions.js";
3
+ export interface ReportExportMenuProps {
4
+ options: ReportExportOption[];
5
+ isLoading?: boolean;
6
+ loadingLabel?: string | null;
7
+ isDisabled?: boolean;
8
+ toggleLabel?: string;
9
+ }
10
+ export declare const ReportExportMenu: FC<ReportExportMenuProps>;
11
+ export interface ExportReportButtonProps extends StandardReportExportHandlers {
12
+ extraOptions?: ReportExportOption[];
13
+ isLoading?: boolean;
14
+ loadingLabel?: string | null;
15
+ isDisabled?: boolean;
16
+ toggleLabel?: string;
17
+ }
18
+ export declare const ExportReportButton: FC<ExportReportButtonProps>;
19
+ //# sourceMappingURL=ReportExportMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportExportMenu.d.ts","sourceRoot":"","sources":["../../src/report/ReportExportMenu.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAE,EAAsB,MAAM,OAAO,CAAC;AACpD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,4BAA4B,EAElC,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CA8DtD,CAAC;AAIF,MAAM,WAAW,uBAAwB,SAAQ,4BAA4B;IAC3E,YAAY,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,uBAAuB,CAkB1D,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Dropdown, DropdownItem, DropdownList, MenuToggle, Spinner, } from "@patternfly/react-core";
3
+ import { DownloadIcon } from "@patternfly/react-icons";
4
+ import { useState } from "react";
5
+ import { standardReportExportOptions, } from "./reportExportOptions.js";
6
+ export const ReportExportMenu = ({ options, isLoading = false, loadingLabel = null, isDisabled = false, toggleLabel = "Export", }) => {
7
+ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
8
+ if (options.length === 0) {
9
+ return null;
10
+ }
11
+ return (_jsx(Dropdown, { isOpen: isDropdownOpen, popperProps: {
12
+ placement: "bottom-end",
13
+ preventOverflow: true,
14
+ }, onSelect: () => {
15
+ setIsDropdownOpen(false);
16
+ }, onOpenChange: (isOpen) => {
17
+ setIsDropdownOpen(isOpen);
18
+ }, toggle: (toggleRef) => (_jsx(MenuToggle, { ref: toggleRef, onClick: () => {
19
+ setIsDropdownOpen((open) => !open);
20
+ }, isExpanded: isDropdownOpen, variant: "secondary", isDisabled: isLoading || isDisabled, "aria-label": "Export report options", icon: isLoading ? (_jsx(Spinner, { size: "sm", "aria-hidden": "true" })) : (_jsx(DownloadIcon, { "aria-hidden": "true" })), children: isLoading ? (loadingLabel ?? "Generating...") : toggleLabel })), children: _jsx(DropdownList, { children: options.map((option) => (_jsx(DropdownItem, { isDisabled: option.isDisabled, description: option.description, onClick: option.onSelect, children: option.label }, option.key))) }) }));
21
+ };
22
+ ReportExportMenu.displayName = "ReportExportMenu";
23
+ export const ExportReportButton = ({ onExportPdf, onExportPng, onExportHtml, extraOptions = [], ...menuProps }) => (_jsx(ReportExportMenu, { options: [
24
+ ...standardReportExportOptions({
25
+ onExportPdf,
26
+ onExportPng,
27
+ onExportHtml,
28
+ }),
29
+ ...extraOptions,
30
+ ], ...menuProps }));
31
+ ExportReportButton.displayName = "ExportReportButton";
@@ -0,0 +1,14 @@
1
+ import type React from "react";
2
+ export interface ReportTableProps<DataItem> {
3
+ columns: string[];
4
+ data: DataItem[];
5
+ fields: Array<keyof DataItem>;
6
+ caption?: string;
7
+ onRowClick?: (item: DataItem) => void;
8
+ clickableFields?: Array<keyof DataItem>;
9
+ }
10
+ export declare function ReportTable<DataItem>(props: ReportTableProps<DataItem>): React.ReactNode;
11
+ export declare namespace ReportTable {
12
+ var displayName: string;
13
+ }
14
+ //# sourceMappingURL=ReportTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportTable.d.ts","sourceRoot":"","sources":["../../src/report/ReportTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,gBAAgB,CAAC,QAAQ;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACtC,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;CACzC;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAClC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GAChC,KAAK,CAAC,SAAS,CA8DjB;yBAhEe,WAAW"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from "@patternfly/react-core";
3
+ import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
4
+ import { tableFullWidthStyle } from "./dashboardStyles.js";
5
+ export function ReportTable(props) {
6
+ const { columns, data, fields, caption, onRowClick, clickableFields = [], } = props;
7
+ const renderCell = (item, field) => {
8
+ const value = item[field];
9
+ if (value === "" || value == null) {
10
+ return "-";
11
+ }
12
+ if (typeof value === "boolean") {
13
+ return value ? "True" : "False";
14
+ }
15
+ // Make field clickable if specified
16
+ if (clickableFields.includes(field) && onRowClick) {
17
+ return (_jsx(Button, { variant: "link", isInline: true, onClick: () => onRowClick(item), style: { padding: 0, fontSize: "inherit" }, children: value }));
18
+ }
19
+ return value;
20
+ };
21
+ return (_jsxs(Table, { variant: "compact", borders: false, className: tableFullWidthStyle, children: [caption && _jsx("caption", { children: caption }), _jsx(Thead, { children: _jsx(Tr, { children: columns.map((name) => (_jsx(Th, { children: name }, name))) }) }), _jsx(Tbody, { children: data.map((item) => (_jsx(Tr, { children: fields.map((f) => (_jsx(Td, { children: renderCell(item, f) }, String(f)))) }, `row-${String(item[fields[0]])}`))) })] }));
22
+ }
23
+ ReportTable.displayName = "ReportTable";
@@ -2,7 +2,6 @@ import type { FC } from "react";
2
2
  import { type SupportTier } from "./osSupportTier.js";
3
3
  interface SupportTierBadgeProps {
4
4
  tier: SupportTier;
5
- isExportMode?: boolean;
6
5
  }
7
6
  export declare const SupportTierBadge: FC<SupportTierBadgeProps>;
8
7
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"SupportTierBadge.d.ts","sourceRoot":"","sources":["../../src/report/SupportTierBadge.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAW5B,UAAU,qBAAqB;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAYD,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAiBtD,CAAC"}
1
+ {"version":3,"file":"SupportTierBadge.d.ts","sourceRoot":"","sources":["../../src/report/SupportTierBadge.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAE5B,UAAU,qBAAqB;IAC7B,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAYtD,CAAC"}
@@ -1,23 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { css } from "@emotion/css";
3
2
  import { Label, Tooltip } from "@patternfly/react-core";
4
3
  import { getSupportTierBadgeColor, getSupportTierBadgeInlineStyle, getSupportTierDefinition, getSupportTierLegendLabel, } from "./osSupportTier.js";
5
- const exportBadgeStyle = css `
6
- display: inline-block;
7
- padding: var(--pf-t--global--spacer--xs) var(--pf-t--global--spacer--sm);
8
- border-radius: var(--pf-t--global--border--radius--pill);
9
- font-size: var(--pf-t--global--font--size--body--sm);
10
- line-height: var(--pf-t--global--font--line-height--body);
11
- white-space: nowrap;
12
- `;
13
- const ExportSupportTierBadge = ({ tier }) => {
14
- const { backgroundColor, color } = getSupportTierBadgeInlineStyle(tier);
15
- return (_jsx("span", { className: exportBadgeStyle, style: { backgroundColor, color }, children: getSupportTierLegendLabel(tier) }));
16
- };
17
- export const SupportTierBadge = ({ tier, isExportMode = false, }) => {
18
- if (isExportMode) {
19
- return _jsx(ExportSupportTierBadge, { tier: tier });
20
- }
21
- return (_jsx(Tooltip, { content: getSupportTierDefinition(tier), children: _jsx("span", { children: _jsx(Label, { color: getSupportTierBadgeColor(tier), isCompact: true, children: getSupportTierLegendLabel(tier) }) }) }));
22
- };
4
+ export const SupportTierBadge = ({ tier }) => (_jsx(Tooltip, { content: getSupportTierDefinition(tier), children: _jsx("span", { children: _jsx(Label, { color: getSupportTierBadgeColor(tier), isCompact: true, style: getSupportTierBadgeInlineStyle(tier), children: getSupportTierLegendLabel(tier) }) }) }));
23
5
  SupportTierBadge.displayName = "SupportTierBadge";
@@ -0,0 +1,9 @@
1
+ import type { FC } from "react";
2
+ import type { ClusterDetailRow, ClusterDetailsModel } from "./infrastructureSummaryModel.js";
3
+ export interface VCenterClusterDetailsProps {
4
+ isAggregateView: boolean;
5
+ rows: ClusterDetailRow[];
6
+ details?: ClusterDetailsModel;
7
+ }
8
+ export declare const VCenterClusterDetails: FC<VCenterClusterDetailsProps>;
9
+ //# sourceMappingURL=VCenterClusterDetails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VCenterClusterDetails.d.ts","sourceRoot":"","sources":["../../src/report/VCenterClusterDetails.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAKhC,OAAO,KAAK,EACV,gBAAgB,EAChB,mBAAmB,EAEpB,MAAM,iCAAiC,CAAC;AAEzC,MAAM,WAAW,0BAA0B;IACzC,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAsKD,eAAO,MAAM,qBAAqB,EAAE,EAAE,CAAC,0BAA0B,CA+BhE,CAAC"}