@openshift-migration-advisor/shared-components 0.25.0 → 0.27.0
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.
- package/README.md +25 -0
- package/dist/report/ChartDownloadButton.d.ts +11 -0
- package/dist/report/ChartDownloadButton.d.ts.map +1 -0
- package/dist/report/ChartDownloadButton.js +24 -0
- package/dist/report/ChartExportProvider.d.ts +22 -0
- package/dist/report/ChartExportProvider.d.ts.map +1 -0
- package/dist/report/ChartExportProvider.js +222 -0
- package/dist/report/ChartExportSurface.d.ts +12 -0
- package/dist/report/ChartExportSurface.d.ts.map +1 -0
- package/dist/report/ChartExportSurface.js +32 -0
- package/dist/report/ErrorTable.d.ts +18 -0
- package/dist/report/ErrorTable.d.ts.map +1 -0
- package/dist/report/ErrorTable.js +20 -0
- package/dist/report/HostPowerStates.d.ts +0 -1
- package/dist/report/HostPowerStates.d.ts.map +1 -1
- package/dist/report/HostPowerStates.js +2 -2
- package/dist/report/HostsOverview.d.ts +13 -0
- package/dist/report/HostsOverview.d.ts.map +1 -0
- package/dist/report/HostsOverview.js +84 -0
- package/dist/report/InfrastructureSummary.d.ts.map +1 -1
- package/dist/report/InfrastructureSummary.js +6 -2
- package/dist/report/NetworkOverview.d.ts +31 -0
- package/dist/report/NetworkOverview.d.ts.map +1 -0
- package/dist/report/NetworkOverview.js +201 -0
- package/dist/report/OSDistribution.d.ts +0 -2
- package/dist/report/OSDistribution.d.ts.map +1 -1
- package/dist/report/OSDistribution.js +8 -5
- package/dist/report/OsUpgradeRecommendationPopover.d.ts +0 -1
- package/dist/report/OsUpgradeRecommendationPopover.d.ts.map +1 -1
- package/dist/report/OsUpgradeRecommendationPopover.js +4 -3
- package/dist/report/PowerStateCard.d.ts +0 -1
- package/dist/report/PowerStateCard.d.ts.map +1 -1
- package/dist/report/PowerStateCard.js +4 -2
- package/dist/report/ReportExportMenu.d.ts +19 -0
- package/dist/report/ReportExportMenu.d.ts.map +1 -0
- package/dist/report/ReportExportMenu.js +31 -0
- package/dist/report/ReportTable.d.ts +14 -0
- package/dist/report/ReportTable.d.ts.map +1 -0
- package/dist/report/ReportTable.js +23 -0
- package/dist/report/SupportTierBadge.d.ts +0 -1
- package/dist/report/SupportTierBadge.d.ts.map +1 -1
- package/dist/report/SupportTierBadge.js +1 -21
- package/dist/report/VCenterClusterDetails.d.ts +0 -1
- package/dist/report/VCenterClusterDetails.d.ts.map +1 -1
- package/dist/report/VCenterClusterDetails.js +9 -4
- package/dist/report/VmPowerStates.d.ts +0 -1
- package/dist/report/VmPowerStates.d.ts.map +1 -1
- package/dist/report/VmPowerStates.js +2 -2
- package/dist/report/WarningsTable.d.ts +9 -0
- package/dist/report/WarningsTable.d.ts.map +1 -0
- package/dist/report/WarningsTable.js +20 -0
- package/dist/report/captureChartElement.d.ts +8 -0
- package/dist/report/captureChartElement.d.ts.map +1 -0
- package/dist/report/captureChartElement.js +284 -0
- package/dist/report/chartExport.d.ts +57 -0
- package/dist/report/chartExport.d.ts.map +1 -0
- package/dist/report/chartExport.js +162 -0
- package/dist/report/chartExportContext.d.ts +28 -0
- package/dist/report/chartExportContext.d.ts.map +1 -0
- package/dist/report/chartExportContext.js +36 -0
- package/dist/report/chartExportFilenames.d.ts +4 -0
- package/dist/report/chartExportFilenames.d.ts.map +1 -0
- package/dist/report/chartExportFilenames.js +16 -0
- package/dist/report/constants.d.ts +2 -0
- package/dist/report/constants.d.ts.map +1 -1
- package/dist/report/constants.js +2 -0
- package/dist/report/dashboardStyles.d.ts +0 -4
- package/dist/report/dashboardStyles.d.ts.map +1 -1
- package/dist/report/dashboardStyles.js +0 -19
- package/dist/report/htmlExport.d.ts +9 -0
- package/dist/report/htmlExport.d.ts.map +1 -0
- package/dist/report/htmlExport.js +65 -0
- package/dist/report/index.d.ts +18 -0
- package/dist/report/index.d.ts.map +1 -1
- package/dist/report/index.js +18 -0
- package/dist/report/pdfExport.d.ts +3 -0
- package/dist/report/pdfExport.d.ts.map +1 -0
- package/dist/report/pdfExport.js +82 -0
- package/dist/report/pdfPage.d.ts +15 -0
- package/dist/report/pdfPage.d.ts.map +1 -0
- package/dist/report/pdfPage.js +44 -0
- package/dist/report/reportExportOptions.d.ts +17 -0
- package/dist/report/reportExportOptions.d.ts.map +1 -0
- package/dist/report/reportExportOptions.js +31 -0
- package/dist/report/zipChartPngs.d.ts +3 -0
- package/dist/report/zipChartPngs.d.ts.map +1 -0
- package/dist/report/zipChartPngs.js +8 -0
- package/package.json +7 -2
- package/src/report/ChartDownloadButton.tsx +59 -0
- package/src/report/ChartExportProvider.tsx +384 -0
- package/src/report/ChartExportSurface.tsx +60 -0
- package/src/report/ErrorTable.tsx +85 -0
- package/src/report/HostPowerStates.tsx +0 -3
- package/src/report/HostsOverview.tsx +185 -0
- package/src/report/InfrastructureSummary.tsx +48 -31
- package/src/report/NetworkOverview.tsx +405 -0
- package/src/report/OSDistribution.tsx +46 -42
- package/src/report/OsUpgradeRecommendationPopover.tsx +3 -4
- package/src/report/PowerStateCard.tsx +49 -36
- package/src/report/ReportExportMenu.tsx +119 -0
- package/src/report/ReportTable.tsx +81 -0
- package/src/report/SupportTierBadge.tsx +12 -40
- package/src/report/VCenterClusterDetails.tsx +38 -16
- package/src/report/VmPowerStates.tsx +0 -3
- package/src/report/WarningsTable.tsx +75 -0
- package/src/report/__tests__/ChartExportProvider.test.tsx +474 -0
- package/src/report/__tests__/HostsOverview.test.tsx +145 -0
- package/src/report/__tests__/InfrastructureSummary.test.tsx +0 -22
- package/src/report/__tests__/NetworkOverview.test.tsx +269 -0
- package/src/report/__tests__/OSDistribution.test.tsx +10 -11
- package/src/report/__tests__/captureChartElement.test.ts +132 -0
- package/src/report/__tests__/chartExportPackagers.test.ts +224 -0
- package/src/report/captureChartElement.ts +368 -0
- package/src/report/chartExport.ts +237 -0
- package/src/report/chartExportContext.tsx +84 -0
- package/src/report/chartExportFilenames.ts +21 -0
- package/src/report/constants.ts +2 -0
- package/src/report/dashboardStyles.ts +0 -23
- package/src/report/htmlExport.ts +83 -0
- package/src/report/index.ts +95 -0
- package/src/report/pdfExport.ts +154 -0
- package/src/report/pdfPage.ts +83 -0
- package/src/report/reportExportOptions.ts +53 -0
- package/src/report/zipChartPngs.ts +10 -0
|
@@ -21,6 +21,9 @@ import { DesktopIcon } from "@patternfly/react-icons";
|
|
|
21
21
|
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
|
|
22
22
|
import type { FC, Ref } from "react";
|
|
23
23
|
import { CardEmptyState } from "./CardEmptyState.js";
|
|
24
|
+
import { ChartHeaderActions } from "./ChartDownloadButton.js";
|
|
25
|
+
import { ChartExportSurface } from "./ChartExportSurface.js";
|
|
26
|
+
import { chartExportHideProps, chartExportScrollProps } from "./chartExport.js";
|
|
24
27
|
import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants.js";
|
|
25
28
|
import { dashboardStyles, tableFullWidthStyle } from "./dashboardStyles.js";
|
|
26
29
|
import { EmptySearchResults } from "./EmptySearchResults.js";
|
|
@@ -43,47 +46,55 @@ const tableScrollStyle = css`
|
|
|
43
46
|
max-height: 350px;
|
|
44
47
|
`;
|
|
45
48
|
|
|
49
|
+
const OS_DISTRIBUTION_CHART_ID = "os-distribution";
|
|
50
|
+
const OS_DISTRIBUTION_TITLE = "Operating system distribution";
|
|
51
|
+
|
|
46
52
|
interface OSDistributionProps {
|
|
47
53
|
osData: Record<string, OSDistributionEntry>;
|
|
48
|
-
isExportMode?: boolean;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
export const OSDistribution: FC<OSDistributionProps> = ({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
<Card
|
|
56
|
-
className={isExportMode ? dashboardStyles.cardPrint : dashboardStyles.card}
|
|
57
|
-
id="os-distribution"
|
|
56
|
+
export const OSDistribution: FC<OSDistributionProps> = ({ osData }) => (
|
|
57
|
+
<ChartExportSurface
|
|
58
|
+
id={OS_DISTRIBUTION_CHART_ID}
|
|
59
|
+
title={OS_DISTRIBUTION_TITLE}
|
|
58
60
|
>
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
61
|
+
<Card className={dashboardStyles.card}>
|
|
62
|
+
<CardTitle>
|
|
63
|
+
<Flex
|
|
64
|
+
justifyContent={{ default: "justifyContentSpaceBetween" }}
|
|
65
|
+
alignItems={{ default: "alignItemsCenter" }}
|
|
66
|
+
>
|
|
67
|
+
<FlexItem>
|
|
68
|
+
<Flex
|
|
69
|
+
alignItems={{ default: "alignItemsCenter" }}
|
|
70
|
+
spaceItems={{ default: "spaceItemsSm" }}
|
|
71
|
+
>
|
|
72
|
+
<FlexItem>
|
|
73
|
+
<DesktopIcon /> Operating Systems
|
|
74
|
+
</FlexItem>
|
|
75
|
+
<FlexItem {...chartExportHideProps}>
|
|
76
|
+
<OsSupportTiersHelpPopover />
|
|
77
|
+
</FlexItem>
|
|
78
|
+
</Flex>
|
|
79
|
+
</FlexItem>
|
|
80
|
+
<ChartHeaderActions
|
|
81
|
+
chartId={OS_DISTRIBUTION_CHART_ID}
|
|
82
|
+
title={OS_DISTRIBUTION_TITLE}
|
|
83
|
+
/>
|
|
84
|
+
</Flex>
|
|
85
|
+
</CardTitle>
|
|
86
|
+
<CardBody>
|
|
87
|
+
<OSBarChart osData={osData} />
|
|
88
|
+
</CardBody>
|
|
89
|
+
</Card>
|
|
90
|
+
</ChartExportSurface>
|
|
76
91
|
);
|
|
77
92
|
|
|
78
93
|
interface OSBarChartProps {
|
|
79
94
|
osData: Record<string, OSDistributionEntry>;
|
|
80
|
-
isExportMode?: boolean;
|
|
81
95
|
}
|
|
82
96
|
|
|
83
|
-
export const OSBarChart: FC<OSBarChartProps> = ({
|
|
84
|
-
osData,
|
|
85
|
-
isExportMode = false,
|
|
86
|
-
}) => {
|
|
97
|
+
export const OSBarChart: FC<OSBarChartProps> = ({ osData }) => {
|
|
87
98
|
const vm = useOsBarChartViewModel(osData);
|
|
88
99
|
|
|
89
100
|
if (vm.tableRows.length === 0) {
|
|
@@ -94,7 +105,7 @@ export const OSBarChart: FC<OSBarChartProps> = ({
|
|
|
94
105
|
|
|
95
106
|
return (
|
|
96
107
|
<>
|
|
97
|
-
{
|
|
108
|
+
<div {...chartExportHideProps}>
|
|
98
109
|
<Toolbar hasNoPadding>
|
|
99
110
|
<ToolbarContent>
|
|
100
111
|
<ToolbarItem>
|
|
@@ -138,7 +149,7 @@ export const OSBarChart: FC<OSBarChartProps> = ({
|
|
|
138
149
|
</ToolbarItem>
|
|
139
150
|
</ToolbarContent>
|
|
140
151
|
</Toolbar>
|
|
141
|
-
|
|
152
|
+
</div>
|
|
142
153
|
|
|
143
154
|
<Stack hasGutter>
|
|
144
155
|
{vm.showUpgradeNotice ? (
|
|
@@ -148,11 +159,8 @@ export const OSBarChart: FC<OSBarChartProps> = ({
|
|
|
148
159
|
) : null}
|
|
149
160
|
<StackItem>
|
|
150
161
|
<div
|
|
151
|
-
className={
|
|
152
|
-
|
|
153
|
-
? tableFullWidthStyle
|
|
154
|
-
: `${tableScrollStyle} ${tableFullWidthStyle}`
|
|
155
|
-
}
|
|
162
|
+
className={`${tableScrollStyle} ${tableFullWidthStyle}`}
|
|
163
|
+
{...chartExportScrollProps}
|
|
156
164
|
>
|
|
157
165
|
<Table aria-label="Operating systems" variant="compact">
|
|
158
166
|
<Thead>
|
|
@@ -176,14 +184,10 @@ export const OSBarChart: FC<OSBarChartProps> = ({
|
|
|
176
184
|
<OsNameCell
|
|
177
185
|
osName={row.osName}
|
|
178
186
|
upgradeRecommendation={row.upgradeRecommendation}
|
|
179
|
-
isExportMode={isExportMode}
|
|
180
187
|
/>
|
|
181
188
|
</Td>
|
|
182
189
|
<Td dataLabel="Tier">
|
|
183
|
-
<SupportTierBadge
|
|
184
|
-
tier={row.tier}
|
|
185
|
-
isExportMode={isExportMode}
|
|
186
|
-
/>
|
|
190
|
+
<SupportTierBadge tier={row.tier} />
|
|
187
191
|
</Td>
|
|
188
192
|
<Td dataLabel="VMs">{row.count}</Td>
|
|
189
193
|
</Tr>
|
|
@@ -2,6 +2,7 @@ import { css } from "@emotion/css";
|
|
|
2
2
|
import { Button, Flex, FlexItem, Popover } from "@patternfly/react-core";
|
|
3
3
|
import { InfoCircleIcon } from "@patternfly/react-icons";
|
|
4
4
|
import type { FC } from "react";
|
|
5
|
+
import { chartExportHideProps } from "./chartExport.js";
|
|
5
6
|
|
|
6
7
|
const upgradeRecommendationPopoverCloseButton = css`
|
|
7
8
|
.pf-v6-c-popover__close .pf-v6-c-button.pf-m-plain,
|
|
@@ -44,18 +45,16 @@ OsUpgradeRecommendationPopover.displayName = "OsUpgradeRecommendationPopover";
|
|
|
44
45
|
interface OsNameCellProps {
|
|
45
46
|
osName: string;
|
|
46
47
|
upgradeRecommendation?: string;
|
|
47
|
-
isExportMode?: boolean;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export const OsNameCell: FC<OsNameCellProps> = ({
|
|
51
51
|
osName,
|
|
52
52
|
upgradeRecommendation,
|
|
53
|
-
isExportMode = false,
|
|
54
53
|
}) => {
|
|
55
54
|
const hasUpgradeRecommendation =
|
|
56
55
|
upgradeRecommendation && upgradeRecommendation.trim() !== "";
|
|
57
56
|
|
|
58
|
-
if (!hasUpgradeRecommendation
|
|
57
|
+
if (!hasUpgradeRecommendation) {
|
|
59
58
|
return <>{osName}</>;
|
|
60
59
|
}
|
|
61
60
|
|
|
@@ -66,7 +65,7 @@ export const OsNameCell: FC<OsNameCellProps> = ({
|
|
|
66
65
|
flexWrap={{ default: "nowrap" }}
|
|
67
66
|
>
|
|
68
67
|
<FlexItem>{osName}</FlexItem>
|
|
69
|
-
<FlexItem shrink={{ default: "shrink" }}>
|
|
68
|
+
<FlexItem shrink={{ default: "shrink" }} {...chartExportHideProps}>
|
|
70
69
|
<OsUpgradeRecommendationPopover
|
|
71
70
|
upgradeRecommendation={upgradeRecommendation}
|
|
72
71
|
/>
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Card,
|
|
3
|
+
CardBody,
|
|
4
|
+
CardTitle,
|
|
5
|
+
Flex,
|
|
6
|
+
FlexItem,
|
|
7
|
+
} from "@patternfly/react-core";
|
|
2
8
|
import type { FC, ReactNode } from "react";
|
|
3
9
|
import {
|
|
4
10
|
MigrationDonutChart,
|
|
@@ -6,6 +12,8 @@ import {
|
|
|
6
12
|
type MigrationDonutChartLegendVariant,
|
|
7
13
|
} from "../charts/MigrationDonutChart.js";
|
|
8
14
|
import { CardEmptyState } from "./CardEmptyState.js";
|
|
15
|
+
import { ChartHeaderActions } from "./ChartDownloadButton.js";
|
|
16
|
+
import { ChartExportSurface } from "./ChartExportSurface.js";
|
|
9
17
|
import { dashboardStyles } from "./dashboardStyles.js";
|
|
10
18
|
|
|
11
19
|
export interface PowerStateCardProps {
|
|
@@ -17,7 +25,6 @@ export interface PowerStateCardProps {
|
|
|
17
25
|
legend: Record<string, string>;
|
|
18
26
|
total: number;
|
|
19
27
|
subTitle: string;
|
|
20
|
-
isExportMode?: boolean;
|
|
21
28
|
itemsPerRow?: number;
|
|
22
29
|
legendVariant?: MigrationDonutChartLegendVariant;
|
|
23
30
|
}
|
|
@@ -31,43 +38,49 @@ export const PowerStateCard: FC<PowerStateCardProps> = ({
|
|
|
31
38
|
legend,
|
|
32
39
|
total,
|
|
33
40
|
subTitle,
|
|
34
|
-
isExportMode = false,
|
|
35
41
|
itemsPerRow = 2,
|
|
36
42
|
legendVariant = "html",
|
|
37
43
|
}) => (
|
|
38
|
-
<
|
|
39
|
-
className={
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
44
|
+
<ChartExportSurface id={id} title={title}>
|
|
45
|
+
<Card className={dashboardStyles.card}>
|
|
46
|
+
<CardTitle>
|
|
47
|
+
<Flex
|
|
48
|
+
justifyContent={{ default: "justifyContentSpaceBetween" }}
|
|
49
|
+
alignItems={{ default: "alignItemsCenter" }}
|
|
50
|
+
>
|
|
51
|
+
<FlexItem>
|
|
52
|
+
{icon} {title}
|
|
53
|
+
</FlexItem>
|
|
54
|
+
<ChartHeaderActions chartId={id} title={title} />
|
|
55
|
+
</Flex>
|
|
56
|
+
</CardTitle>
|
|
57
|
+
<CardBody>
|
|
58
|
+
{total === 0 ? (
|
|
59
|
+
<CardEmptyState title={emptyTitle} />
|
|
60
|
+
) : (
|
|
61
|
+
<MigrationDonutChart
|
|
62
|
+
legendVariant={legendVariant}
|
|
63
|
+
data={slices}
|
|
64
|
+
legend={legend}
|
|
65
|
+
height={300}
|
|
66
|
+
width={420}
|
|
67
|
+
donutThickness={18}
|
|
68
|
+
padAngle={1}
|
|
69
|
+
title={`${total}`}
|
|
70
|
+
subTitle={subTitle}
|
|
71
|
+
subTitleColor="var(--pf-t--global--text--color--subtle)"
|
|
72
|
+
titleFontSize={34}
|
|
73
|
+
labelFontSize={16}
|
|
74
|
+
itemsPerRow={itemsPerRow}
|
|
75
|
+
marginLeft="0%"
|
|
76
|
+
tooltipLabelFormatter={({ datum, percent }) =>
|
|
77
|
+
`${datum.countDisplay}\n${percent.toFixed(1)}%`
|
|
78
|
+
}
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
81
|
+
</CardBody>
|
|
82
|
+
</Card>
|
|
83
|
+
</ChartExportSurface>
|
|
71
84
|
);
|
|
72
85
|
|
|
73
86
|
PowerStateCard.displayName = "PowerStateCard";
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Dropdown,
|
|
3
|
+
DropdownItem,
|
|
4
|
+
DropdownList,
|
|
5
|
+
MenuToggle,
|
|
6
|
+
type MenuToggleElement,
|
|
7
|
+
Spinner,
|
|
8
|
+
} from "@patternfly/react-core";
|
|
9
|
+
import { DownloadIcon } from "@patternfly/react-icons";
|
|
10
|
+
import { type FC, type Ref, useState } from "react";
|
|
11
|
+
import {
|
|
12
|
+
type ReportExportOption,
|
|
13
|
+
type StandardReportExportHandlers,
|
|
14
|
+
standardReportExportOptions,
|
|
15
|
+
} from "./reportExportOptions.js";
|
|
16
|
+
|
|
17
|
+
export interface ReportExportMenuProps {
|
|
18
|
+
options: ReportExportOption[];
|
|
19
|
+
isLoading?: boolean;
|
|
20
|
+
loadingLabel?: string | null;
|
|
21
|
+
isDisabled?: boolean;
|
|
22
|
+
toggleLabel?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const ReportExportMenu: FC<ReportExportMenuProps> = ({
|
|
26
|
+
options,
|
|
27
|
+
isLoading = false,
|
|
28
|
+
loadingLabel = null,
|
|
29
|
+
isDisabled = false,
|
|
30
|
+
toggleLabel = "Export",
|
|
31
|
+
}) => {
|
|
32
|
+
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
|
33
|
+
|
|
34
|
+
if (options.length === 0) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Dropdown
|
|
40
|
+
isOpen={isDropdownOpen}
|
|
41
|
+
popperProps={{
|
|
42
|
+
placement: "bottom-end",
|
|
43
|
+
preventOverflow: true,
|
|
44
|
+
}}
|
|
45
|
+
onSelect={() => {
|
|
46
|
+
setIsDropdownOpen(false);
|
|
47
|
+
}}
|
|
48
|
+
onOpenChange={(isOpen: boolean) => {
|
|
49
|
+
setIsDropdownOpen(isOpen);
|
|
50
|
+
}}
|
|
51
|
+
toggle={(toggleRef: Ref<MenuToggleElement>) => (
|
|
52
|
+
<MenuToggle
|
|
53
|
+
ref={toggleRef}
|
|
54
|
+
onClick={() => {
|
|
55
|
+
setIsDropdownOpen((open) => !open);
|
|
56
|
+
}}
|
|
57
|
+
isExpanded={isDropdownOpen}
|
|
58
|
+
variant="secondary"
|
|
59
|
+
isDisabled={isLoading || isDisabled}
|
|
60
|
+
aria-label="Export report options"
|
|
61
|
+
icon={
|
|
62
|
+
isLoading ? (
|
|
63
|
+
<Spinner size="sm" aria-hidden="true" />
|
|
64
|
+
) : (
|
|
65
|
+
<DownloadIcon aria-hidden="true" />
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
>
|
|
69
|
+
{isLoading ? (loadingLabel ?? "Generating...") : toggleLabel}
|
|
70
|
+
</MenuToggle>
|
|
71
|
+
)}
|
|
72
|
+
>
|
|
73
|
+
<DropdownList>
|
|
74
|
+
{options.map((option) => (
|
|
75
|
+
<DropdownItem
|
|
76
|
+
key={option.key}
|
|
77
|
+
isDisabled={option.isDisabled}
|
|
78
|
+
description={option.description}
|
|
79
|
+
onClick={option.onSelect}
|
|
80
|
+
>
|
|
81
|
+
{option.label}
|
|
82
|
+
</DropdownItem>
|
|
83
|
+
))}
|
|
84
|
+
</DropdownList>
|
|
85
|
+
</Dropdown>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
ReportExportMenu.displayName = "ReportExportMenu";
|
|
90
|
+
|
|
91
|
+
export interface ExportReportButtonProps extends StandardReportExportHandlers {
|
|
92
|
+
extraOptions?: ReportExportOption[];
|
|
93
|
+
isLoading?: boolean;
|
|
94
|
+
loadingLabel?: string | null;
|
|
95
|
+
isDisabled?: boolean;
|
|
96
|
+
toggleLabel?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const ExportReportButton: FC<ExportReportButtonProps> = ({
|
|
100
|
+
onExportPdf,
|
|
101
|
+
onExportPng,
|
|
102
|
+
onExportHtml,
|
|
103
|
+
extraOptions = [],
|
|
104
|
+
...menuProps
|
|
105
|
+
}) => (
|
|
106
|
+
<ReportExportMenu
|
|
107
|
+
options={[
|
|
108
|
+
...standardReportExportOptions({
|
|
109
|
+
onExportPdf,
|
|
110
|
+
onExportPng,
|
|
111
|
+
onExportHtml,
|
|
112
|
+
}),
|
|
113
|
+
...extraOptions,
|
|
114
|
+
]}
|
|
115
|
+
{...menuProps}
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
ExportReportButton.displayName = "ExportReportButton";
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Button } from "@patternfly/react-core";
|
|
2
|
+
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
|
|
3
|
+
import type React from "react";
|
|
4
|
+
import { tableFullWidthStyle } from "./dashboardStyles.js";
|
|
5
|
+
|
|
6
|
+
export interface ReportTableProps<DataItem> {
|
|
7
|
+
columns: string[];
|
|
8
|
+
data: DataItem[];
|
|
9
|
+
fields: Array<keyof DataItem>;
|
|
10
|
+
caption?: string;
|
|
11
|
+
onRowClick?: (item: DataItem) => void;
|
|
12
|
+
clickableFields?: Array<keyof DataItem>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function ReportTable<DataItem>(
|
|
16
|
+
props: ReportTableProps<DataItem>,
|
|
17
|
+
): React.ReactNode {
|
|
18
|
+
const {
|
|
19
|
+
columns,
|
|
20
|
+
data,
|
|
21
|
+
fields,
|
|
22
|
+
caption,
|
|
23
|
+
onRowClick,
|
|
24
|
+
clickableFields = [],
|
|
25
|
+
} = props;
|
|
26
|
+
|
|
27
|
+
const renderCell = (
|
|
28
|
+
item: DataItem,
|
|
29
|
+
field: keyof DataItem,
|
|
30
|
+
): React.ReactNode => {
|
|
31
|
+
const value = item[field];
|
|
32
|
+
|
|
33
|
+
if (value === "" || value == null) {
|
|
34
|
+
return "-";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (typeof value === "boolean") {
|
|
38
|
+
return value ? "True" : "False";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Make field clickable if specified
|
|
42
|
+
if (clickableFields.includes(field) && onRowClick) {
|
|
43
|
+
return (
|
|
44
|
+
<Button
|
|
45
|
+
variant="link"
|
|
46
|
+
isInline
|
|
47
|
+
onClick={() => onRowClick(item)}
|
|
48
|
+
style={{ padding: 0, fontSize: "inherit" }}
|
|
49
|
+
>
|
|
50
|
+
{value as React.ReactNode}
|
|
51
|
+
</Button>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return value as React.ReactNode;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Table variant="compact" borders={false} className={tableFullWidthStyle}>
|
|
60
|
+
{caption && <caption>{caption}</caption>}
|
|
61
|
+
<Thead>
|
|
62
|
+
<Tr>
|
|
63
|
+
{columns.map((name) => (
|
|
64
|
+
<Th key={name}>{name}</Th>
|
|
65
|
+
))}
|
|
66
|
+
</Tr>
|
|
67
|
+
</Thead>
|
|
68
|
+
<Tbody>
|
|
69
|
+
{data.map((item) => (
|
|
70
|
+
<Tr key={`row-${String(item[fields[0]])}`}>
|
|
71
|
+
{fields.map((f) => (
|
|
72
|
+
<Td key={String(f)}>{renderCell(item, f)}</Td>
|
|
73
|
+
))}
|
|
74
|
+
</Tr>
|
|
75
|
+
))}
|
|
76
|
+
</Tbody>
|
|
77
|
+
</Table>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ReportTable.displayName = "ReportTable";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { css } from "@emotion/css";
|
|
2
1
|
import { Label, Tooltip } from "@patternfly/react-core";
|
|
3
2
|
import type { FC } from "react";
|
|
4
3
|
import {
|
|
@@ -9,49 +8,22 @@ import {
|
|
|
9
8
|
type SupportTier,
|
|
10
9
|
} from "./osSupportTier.js";
|
|
11
10
|
|
|
12
|
-
const exportBadgeStyle = (backgroundColor: string, color: string) => css`
|
|
13
|
-
display: inline-block;
|
|
14
|
-
padding: var(--pf-t--global--spacer--xs) var(--pf-t--global--spacer--sm);
|
|
15
|
-
border-radius: var(--pf-t--global--border--radius--pill);
|
|
16
|
-
font-size: var(--pf-t--global--font--size--body--sm);
|
|
17
|
-
line-height: var(--pf-t--global--font--line-height--body);
|
|
18
|
-
white-space: nowrap;
|
|
19
|
-
background-color: ${backgroundColor};
|
|
20
|
-
color: ${color};
|
|
21
|
-
`;
|
|
22
|
-
|
|
23
11
|
interface SupportTierBadgeProps {
|
|
24
12
|
tier: SupportTier;
|
|
25
|
-
isExportMode?: boolean;
|
|
26
13
|
}
|
|
27
14
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
export const SupportTierBadge: FC<SupportTierBadgeProps> = ({ tier }) => (
|
|
16
|
+
<Tooltip content={getSupportTierDefinition(tier)}>
|
|
17
|
+
<span>
|
|
18
|
+
<Label
|
|
19
|
+
color={getSupportTierBadgeColor(tier)}
|
|
20
|
+
isCompact
|
|
21
|
+
style={getSupportTierBadgeInlineStyle(tier)}
|
|
22
|
+
>
|
|
23
|
+
{getSupportTierLegendLabel(tier)}
|
|
24
|
+
</Label>
|
|
34
25
|
</span>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
export const SupportTierBadge: FC<SupportTierBadgeProps> = ({
|
|
39
|
-
tier,
|
|
40
|
-
isExportMode = false,
|
|
41
|
-
}) => {
|
|
42
|
-
if (isExportMode) {
|
|
43
|
-
return <ExportSupportTierBadge tier={tier} />;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
<Tooltip content={getSupportTierDefinition(tier)}>
|
|
48
|
-
<span>
|
|
49
|
-
<Label color={getSupportTierBadgeColor(tier)} isCompact>
|
|
50
|
-
{getSupportTierLegendLabel(tier)}
|
|
51
|
-
</Label>
|
|
52
|
-
</span>
|
|
53
|
-
</Tooltip>
|
|
54
|
-
);
|
|
55
|
-
};
|
|
26
|
+
</Tooltip>
|
|
27
|
+
);
|
|
56
28
|
|
|
57
29
|
SupportTierBadge.displayName = "SupportTierBadge";
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
DescriptionListDescription,
|
|
9
9
|
DescriptionListGroup,
|
|
10
10
|
DescriptionListTerm,
|
|
11
|
+
Flex,
|
|
12
|
+
FlexItem,
|
|
11
13
|
Grid,
|
|
12
14
|
GridItem,
|
|
13
15
|
Label,
|
|
@@ -15,6 +17,9 @@ import {
|
|
|
15
17
|
} from "@patternfly/react-core";
|
|
16
18
|
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
|
|
17
19
|
import type { FC } from "react";
|
|
20
|
+
import { ChartHeaderActions } from "./ChartDownloadButton.js";
|
|
21
|
+
import { ChartExportSurface } from "./ChartExportSurface.js";
|
|
22
|
+
import { chartExportScrollProps } from "./chartExport.js";
|
|
18
23
|
import { FeatureStatusBadge } from "./FeatureStatusBadge.js";
|
|
19
24
|
import type {
|
|
20
25
|
ClusterDetailRow,
|
|
@@ -26,7 +31,6 @@ export interface VCenterClusterDetailsProps {
|
|
|
26
31
|
isAggregateView: boolean;
|
|
27
32
|
rows: ClusterDetailRow[];
|
|
28
33
|
details?: ClusterDetailsModel;
|
|
29
|
-
isExportMode?: boolean;
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
const clusterDetailsTableScrollStyle = css`
|
|
@@ -91,16 +95,16 @@ const AggregateClusterTable: FC<{
|
|
|
91
95
|
|
|
92
96
|
const AggregateCluster: FC<{
|
|
93
97
|
rows: ClusterDetailRow[];
|
|
94
|
-
|
|
95
|
-
}> = ({ rows, isExportMode }) => {
|
|
98
|
+
}> = ({ rows }) => {
|
|
96
99
|
if (rows.length === 0) {
|
|
97
100
|
return <Content component="p">No vSphere clusters detected</Content>;
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
return (
|
|
101
104
|
<div
|
|
102
|
-
className={
|
|
103
|
-
data-scroll-constrained=
|
|
105
|
+
className={clusterDetailsTableScrollStyle}
|
|
106
|
+
data-scroll-constrained="true"
|
|
107
|
+
{...chartExportScrollProps}
|
|
104
108
|
>
|
|
105
109
|
<AggregateClusterTable rows={rows} />
|
|
106
110
|
</div>
|
|
@@ -190,22 +194,40 @@ const DetailedClusterView: FC<{ details: ClusterDetailsModel }> = ({
|
|
|
190
194
|
</Grid>
|
|
191
195
|
);
|
|
192
196
|
|
|
197
|
+
const CLUSTER_DETAILS_CHART_ID = "vcenter-cluster-details";
|
|
198
|
+
const CLUSTER_DETAILS_TITLE = "vCenter cluster details";
|
|
199
|
+
|
|
193
200
|
export const VCenterClusterDetails: FC<VCenterClusterDetailsProps> = ({
|
|
194
201
|
isAggregateView,
|
|
195
202
|
rows,
|
|
196
203
|
details,
|
|
197
|
-
isExportMode = false,
|
|
198
204
|
}) => (
|
|
199
|
-
<
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
205
|
+
<ChartExportSurface
|
|
206
|
+
id={CLUSTER_DETAILS_CHART_ID}
|
|
207
|
+
title={CLUSTER_DETAILS_TITLE}
|
|
208
|
+
>
|
|
209
|
+
<Card isFullHeight>
|
|
210
|
+
<CardTitle>
|
|
211
|
+
<Flex
|
|
212
|
+
justifyContent={{ default: "justifyContentSpaceBetween" }}
|
|
213
|
+
alignItems={{ default: "alignItemsCenter" }}
|
|
214
|
+
>
|
|
215
|
+
<FlexItem>{CLUSTER_DETAILS_TITLE}</FlexItem>
|
|
216
|
+
<ChartHeaderActions
|
|
217
|
+
chartId={CLUSTER_DETAILS_CHART_ID}
|
|
218
|
+
title={CLUSTER_DETAILS_TITLE}
|
|
219
|
+
/>
|
|
220
|
+
</Flex>
|
|
221
|
+
</CardTitle>
|
|
222
|
+
<CardBody>
|
|
223
|
+
{isAggregateView || !details ? (
|
|
224
|
+
<AggregateCluster rows={rows} />
|
|
225
|
+
) : (
|
|
226
|
+
<DetailedClusterView details={details} />
|
|
227
|
+
)}
|
|
228
|
+
</CardBody>
|
|
229
|
+
</Card>
|
|
230
|
+
</ChartExportSurface>
|
|
209
231
|
);
|
|
210
232
|
|
|
211
233
|
VCenterClusterDetails.displayName = "VCenterClusterDetails";
|
|
@@ -8,13 +8,11 @@ import { buildVmPowerStateChart } from "./powerStates.js";
|
|
|
8
8
|
|
|
9
9
|
export interface VmPowerStatesProps {
|
|
10
10
|
powerStates?: Record<string, number>;
|
|
11
|
-
isExportMode?: boolean;
|
|
12
11
|
legendVariant?: MigrationDonutChartLegendVariant;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
export const VmPowerStates: FC<VmPowerStatesProps> = ({
|
|
16
15
|
powerStates,
|
|
17
|
-
isExportMode = false,
|
|
18
16
|
legendVariant,
|
|
19
17
|
}) => {
|
|
20
18
|
const chart = useMemo(
|
|
@@ -32,7 +30,6 @@ export const VmPowerStates: FC<VmPowerStatesProps> = ({
|
|
|
32
30
|
legend={chart.legend}
|
|
33
31
|
total={chart.total}
|
|
34
32
|
subTitle="VMs"
|
|
35
|
-
isExportMode={isExportMode}
|
|
36
33
|
legendVariant={legendVariant}
|
|
37
34
|
/>
|
|
38
35
|
);
|