@openshift-migration-advisor/shared-components 0.24.0 → 0.25.0-6a4104ca5ed2

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 (130) 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 +22 -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/FeatureStatusBadge.d.ts +7 -0
  16. package/dist/report/FeatureStatusBadge.d.ts.map +1 -0
  17. package/dist/report/FeatureStatusBadge.js +13 -0
  18. package/dist/report/HostPowerStates.d.ts +8 -0
  19. package/dist/report/HostPowerStates.d.ts.map +1 -0
  20. package/dist/report/HostPowerStates.js +11 -0
  21. package/dist/report/InfrastructureSummary.d.ts +7 -0
  22. package/dist/report/InfrastructureSummary.d.ts.map +1 -0
  23. package/dist/report/InfrastructureSummary.js +9 -0
  24. package/dist/report/OSDistribution.d.ts +0 -2
  25. package/dist/report/OSDistribution.d.ts.map +1 -1
  26. package/dist/report/OSDistribution.js +10 -15
  27. package/dist/report/OsSupportTiersHelpPopover.d.ts.map +1 -1
  28. package/dist/report/OsSupportTiersHelpPopover.js +2 -31
  29. package/dist/report/OsUpgradeNotice.d.ts.map +1 -1
  30. package/dist/report/OsUpgradeNotice.js +1 -5
  31. package/dist/report/OsUpgradeRecommendationPopover.d.ts +0 -1
  32. package/dist/report/OsUpgradeRecommendationPopover.d.ts.map +1 -1
  33. package/dist/report/OsUpgradeRecommendationPopover.js +4 -3
  34. package/dist/report/PowerStateCard.d.ts +16 -0
  35. package/dist/report/PowerStateCard.d.ts.map +1 -0
  36. package/dist/report/PowerStateCard.js +9 -0
  37. package/dist/report/ReportExportMenu.d.ts +19 -0
  38. package/dist/report/ReportExportMenu.d.ts.map +1 -0
  39. package/dist/report/ReportExportMenu.js +31 -0
  40. package/dist/report/SupportTierBadge.d.ts +0 -1
  41. package/dist/report/SupportTierBadge.d.ts.map +1 -1
  42. package/dist/report/SupportTierBadge.js +1 -19
  43. package/dist/report/VCenterClusterDetails.d.ts +9 -0
  44. package/dist/report/VCenterClusterDetails.d.ts.map +1 -0
  45. package/dist/report/VCenterClusterDetails.js +31 -0
  46. package/dist/report/VmPowerStates.d.ts +8 -0
  47. package/dist/report/VmPowerStates.d.ts.map +1 -0
  48. package/dist/report/VmPowerStates.js +11 -0
  49. package/dist/report/captureChartElement.d.ts +8 -0
  50. package/dist/report/captureChartElement.d.ts.map +1 -0
  51. package/dist/report/captureChartElement.js +264 -0
  52. package/dist/report/chartExport.d.ts +57 -0
  53. package/dist/report/chartExport.d.ts.map +1 -0
  54. package/dist/report/chartExport.js +159 -0
  55. package/dist/report/chartExportContext.d.ts +28 -0
  56. package/dist/report/chartExportContext.d.ts.map +1 -0
  57. package/dist/report/chartExportContext.js +36 -0
  58. package/dist/report/chartExportFilenames.d.ts +4 -0
  59. package/dist/report/chartExportFilenames.d.ts.map +1 -0
  60. package/dist/report/chartExportFilenames.js +16 -0
  61. package/dist/report/constants.d.ts +2 -0
  62. package/dist/report/constants.d.ts.map +1 -1
  63. package/dist/report/constants.js +2 -0
  64. package/dist/report/dashboardStyles.d.ts +0 -4
  65. package/dist/report/dashboardStyles.d.ts.map +1 -1
  66. package/dist/report/dashboardStyles.js +0 -19
  67. package/dist/report/htmlExport.d.ts +9 -0
  68. package/dist/report/htmlExport.d.ts.map +1 -0
  69. package/dist/report/htmlExport.js +67 -0
  70. package/dist/report/index.d.ts +23 -0
  71. package/dist/report/index.d.ts.map +1 -1
  72. package/dist/report/index.js +21 -0
  73. package/dist/report/infrastructureSummaryModel.d.ts +82 -0
  74. package/dist/report/infrastructureSummaryModel.d.ts.map +1 -0
  75. package/dist/report/infrastructureSummaryModel.js +139 -0
  76. package/dist/report/pdfExport.d.ts +3 -0
  77. package/dist/report/pdfExport.d.ts.map +1 -0
  78. package/dist/report/pdfExport.js +87 -0
  79. package/dist/report/pdfPage.d.ts +7 -0
  80. package/dist/report/pdfPage.d.ts.map +1 -0
  81. package/dist/report/pdfPage.js +27 -0
  82. package/dist/report/powerStates.d.ts +11 -0
  83. package/dist/report/powerStates.d.ts.map +1 -0
  84. package/dist/report/powerStates.js +113 -0
  85. package/dist/report/reportExportOptions.d.ts +17 -0
  86. package/dist/report/reportExportOptions.d.ts.map +1 -0
  87. package/dist/report/reportExportOptions.js +31 -0
  88. package/dist/report/zipChartPngs.d.ts +3 -0
  89. package/dist/report/zipChartPngs.d.ts.map +1 -0
  90. package/dist/report/zipChartPngs.js +8 -0
  91. package/package.json +7 -2
  92. package/src/charts/index.ts +1 -0
  93. package/src/forms/RadioButtonFormGroup.tsx +10 -3
  94. package/src/report/ChartDownloadButton.tsx +59 -0
  95. package/src/report/ChartExportProvider.tsx +384 -0
  96. package/src/report/ChartExportSurface.tsx +60 -0
  97. package/src/report/FeatureStatusBadge.tsx +30 -0
  98. package/src/report/HostPowerStates.tsx +38 -0
  99. package/src/report/InfrastructureSummary.tsx +73 -0
  100. package/src/report/OSDistribution.tsx +96 -99
  101. package/src/report/OsSupportTiersHelpPopover.tsx +32 -62
  102. package/src/report/OsUpgradeNotice.tsx +1 -7
  103. package/src/report/OsUpgradeRecommendationPopover.tsx +3 -4
  104. package/src/report/PowerStateCard.tsx +86 -0
  105. package/src/report/ReportExportMenu.tsx +119 -0
  106. package/src/report/SupportTierBadge.tsx +12 -38
  107. package/src/report/VCenterClusterDetails.tsx +233 -0
  108. package/src/report/VmPowerStates.tsx +38 -0
  109. package/src/report/__tests__/ChartExportProvider.test.tsx +474 -0
  110. package/src/report/__tests__/HostPowerStates.test.tsx +47 -0
  111. package/src/report/__tests__/InfrastructureSummary.test.tsx +126 -0
  112. package/src/report/__tests__/OSDistribution.test.tsx +10 -11
  113. package/src/report/__tests__/captureChartElement.test.ts +132 -0
  114. package/src/report/__tests__/chartExportPackagers.test.ts +185 -0
  115. package/src/report/__tests__/infrastructureSummaryModel.test.ts +224 -0
  116. package/src/report/__tests__/powerStates.test.ts +70 -0
  117. package/src/report/captureChartElement.ts +351 -0
  118. package/src/report/chartExport.ts +234 -0
  119. package/src/report/chartExportContext.tsx +84 -0
  120. package/src/report/chartExportFilenames.ts +21 -0
  121. package/src/report/constants.ts +2 -0
  122. package/src/report/dashboardStyles.ts +0 -23
  123. package/src/report/htmlExport.ts +85 -0
  124. package/src/report/index.ts +128 -0
  125. package/src/report/infrastructureSummaryModel.ts +281 -0
  126. package/src/report/pdfExport.ts +161 -0
  127. package/src/report/pdfPage.ts +54 -0
  128. package/src/report/powerStates.ts +169 -0
  129. package/src/report/reportExportOptions.ts +53 -0
  130. package/src/report/zipChartPngs.ts +10 -0
@@ -11,6 +11,8 @@ import {
11
11
  Select,
12
12
  SelectList,
13
13
  SelectOption,
14
+ Stack,
15
+ StackItem,
14
16
  Toolbar,
15
17
  ToolbarContent,
16
18
  ToolbarItem,
@@ -19,6 +21,9 @@ import { DesktopIcon } from "@patternfly/react-icons";
19
21
  import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
20
22
  import type { FC, Ref } from "react";
21
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";
22
27
  import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants.js";
23
28
  import { dashboardStyles, tableFullWidthStyle } from "./dashboardStyles.js";
24
29
  import { EmptySearchResults } from "./EmptySearchResults.js";
@@ -36,65 +41,60 @@ import {
36
41
  useOsBarChartViewModel,
37
42
  } from "./useOsBarChartViewModel.js";
38
43
 
39
- const filterToolbarStyle = css`
40
- padding-left: 0;
41
- padding-right: 0;
42
- `;
43
-
44
- const filterItemStyle = css`
45
- flex: 1 1 0;
46
- min-width: 0;
47
- `;
48
-
49
- const vmsColumnStyle = css`
50
- text-align: right;
51
- `;
52
-
53
44
  const tableScrollStyle = css`
54
45
  overflow: auto;
46
+ max-height: 350px;
55
47
  `;
56
48
 
49
+ const OS_DISTRIBUTION_CHART_ID = "os-distribution";
50
+ const OS_DISTRIBUTION_TITLE = "Operating system distribution";
51
+
57
52
  interface OSDistributionProps {
58
53
  osData: Record<string, OSDistributionEntry>;
59
- isExportMode?: boolean;
60
54
  }
61
55
 
62
- export const OSDistribution: FC<OSDistributionProps> = ({
63
- osData,
64
- isExportMode = false,
65
- }) => (
66
- <Card
67
- className={isExportMode ? dashboardStyles.cardPrint : dashboardStyles.card}
68
- id="os-distribution"
56
+ export const OSDistribution: FC<OSDistributionProps> = ({ osData }) => (
57
+ <ChartExportSurface
58
+ id={OS_DISTRIBUTION_CHART_ID}
59
+ title={OS_DISTRIBUTION_TITLE}
69
60
  >
70
- <CardTitle>
71
- <Flex
72
- alignItems={{ default: "alignItemsCenter" }}
73
- spaceItems={{ default: "spaceItemsSm" }}
74
- >
75
- <FlexItem>
76
- <DesktopIcon /> Operating Systems
77
- </FlexItem>
78
- <FlexItem>
79
- <OsSupportTiersHelpPopover />
80
- </FlexItem>
81
- </Flex>
82
- </CardTitle>
83
- <CardBody>
84
- <OSBarChart osData={osData} isExportMode={isExportMode} />
85
- </CardBody>
86
- </Card>
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>
87
91
  );
88
92
 
89
93
  interface OSBarChartProps {
90
94
  osData: Record<string, OSDistributionEntry>;
91
- isExportMode?: boolean;
92
95
  }
93
96
 
94
- export const OSBarChart: FC<OSBarChartProps> = ({
95
- osData,
96
- isExportMode = false,
97
- }) => {
97
+ export const OSBarChart: FC<OSBarChartProps> = ({ osData }) => {
98
98
  const vm = useOsBarChartViewModel(osData);
99
99
 
100
100
  if (vm.tableRows.length === 0) {
@@ -105,10 +105,10 @@ export const OSBarChart: FC<OSBarChartProps> = ({
105
105
 
106
106
  return (
107
107
  <>
108
- {!isExportMode ? (
109
- <Toolbar className={filterToolbarStyle}>
108
+ <div {...chartExportHideProps}>
109
+ <Toolbar hasNoPadding>
110
110
  <ToolbarContent>
111
- <ToolbarItem className={filterItemStyle}>
111
+ <ToolbarItem>
112
112
  <SearchInput
113
113
  placeholder="Filter by OS"
114
114
  value={vm.osFilter}
@@ -117,7 +117,7 @@ export const OSBarChart: FC<OSBarChartProps> = ({
117
117
  aria-label="Filter operating systems by name"
118
118
  />
119
119
  </ToolbarItem>
120
- <ToolbarItem className={filterItemStyle}>
120
+ <ToolbarItem>
121
121
  <Select
122
122
  isOpen={vm.isTierSelectOpen}
123
123
  selected={vm.tierFilter}
@@ -128,7 +128,7 @@ export const OSBarChart: FC<OSBarChartProps> = ({
128
128
  ref={toggleRef}
129
129
  isExpanded={vm.isTierSelectOpen}
130
130
  onClick={vm.toggleTierSelectOpen}
131
- style={{ width: "100%" }}
131
+ isFullWidth
132
132
  >
133
133
  {vm.tierFilterLabel}
134
134
  </MenuToggle>
@@ -149,58 +149,55 @@ export const OSBarChart: FC<OSBarChartProps> = ({
149
149
  </ToolbarItem>
150
150
  </ToolbarContent>
151
151
  </Toolbar>
152
- ) : null}
153
-
154
- {vm.showUpgradeNotice ? <OsUpgradeNotice /> : null}
152
+ </div>
155
153
 
156
- <div
157
- className={isExportMode ? undefined : tableScrollStyle}
158
- style={isExportMode ? undefined : { maxHeight: "350px" }}
159
- >
160
- <Table
161
- aria-label="Operating systems"
162
- variant="compact"
163
- className={tableFullWidthStyle}
164
- >
165
- <Thead>
166
- <Tr>
167
- <Th>OS</Th>
168
- <Th>Tier</Th>
169
- <Th className={vmsColumnStyle}>VMs</Th>
170
- </Tr>
171
- </Thead>
172
- <Tbody>
173
- {vm.showNoResults ? (
174
- <Tr>
175
- <Td colSpan={3}>
176
- <EmptySearchResults title="No matching operating system found" />
177
- </Td>
178
- </Tr>
179
- ) : (
180
- vm.filteredRows.map((row) => (
181
- <Tr key={row.osName}>
182
- <Td dataLabel="OS">
183
- <OsNameCell
184
- osName={row.osName}
185
- upgradeRecommendation={row.upgradeRecommendation}
186
- isExportMode={isExportMode}
187
- />
188
- </Td>
189
- <Td dataLabel="Tier">
190
- <SupportTierBadge
191
- tier={row.tier}
192
- isExportMode={isExportMode}
193
- />
194
- </Td>
195
- <Td dataLabel="VMs" className={vmsColumnStyle}>
196
- {row.count}
197
- </Td>
154
+ <Stack hasGutter>
155
+ {vm.showUpgradeNotice ? (
156
+ <StackItem>
157
+ <OsUpgradeNotice />
158
+ </StackItem>
159
+ ) : null}
160
+ <StackItem>
161
+ <div
162
+ className={`${tableScrollStyle} ${tableFullWidthStyle}`}
163
+ {...chartExportScrollProps}
164
+ >
165
+ <Table aria-label="Operating systems" variant="compact">
166
+ <Thead>
167
+ <Tr>
168
+ <Th>OS</Th>
169
+ <Th>Tier</Th>
170
+ <Th>VMs</Th>
198
171
  </Tr>
199
- ))
200
- )}
201
- </Tbody>
202
- </Table>
203
- </div>
172
+ </Thead>
173
+ <Tbody>
174
+ {vm.showNoResults ? (
175
+ <Tr>
176
+ <Td colSpan={3}>
177
+ <EmptySearchResults title="No matching operating system found" />
178
+ </Td>
179
+ </Tr>
180
+ ) : (
181
+ vm.filteredRows.map((row) => (
182
+ <Tr key={row.osName}>
183
+ <Td dataLabel="OS">
184
+ <OsNameCell
185
+ osName={row.osName}
186
+ upgradeRecommendation={row.upgradeRecommendation}
187
+ />
188
+ </Td>
189
+ <Td dataLabel="Tier">
190
+ <SupportTierBadge tier={row.tier} />
191
+ </Td>
192
+ <Td dataLabel="VMs">{row.count}</Td>
193
+ </Tr>
194
+ ))
195
+ )}
196
+ </Tbody>
197
+ </Table>
198
+ </div>
199
+ </StackItem>
200
+ </Stack>
204
201
  </>
205
202
  );
206
203
  };
@@ -1,5 +1,10 @@
1
- import { css } from "@emotion/css";
2
- import { Label } from "@patternfly/react-core";
1
+ import {
2
+ Button,
3
+ Content,
4
+ Label,
5
+ Stack,
6
+ StackItem,
7
+ } from "@patternfly/react-core";
3
8
  import { ExternalLinkAltIcon } from "@patternfly/react-icons";
4
9
  import type { FC } from "react";
5
10
  import {
@@ -11,67 +16,32 @@ import {
11
16
  } from "./osSupportTier.js";
12
17
  import PopoverIcon from "./PopoverIcon.js";
13
18
 
14
- const tierListStyle = css`
15
- list-style: none;
16
- padding: 0;
17
- margin: 0;
18
- display: flex;
19
- flex-direction: column;
20
- gap: var(--pf-t--global--spacer--400);
21
- `;
22
-
23
- const tierItemStyle = css`
24
- display: flex;
25
- flex-direction: column;
26
- gap: var(--pf-t--global--spacer--100);
27
- `;
28
-
29
- const tierBadgeStyle = css`
30
- width: fit-content;
31
- max-width: 100%;
32
- align-self: flex-start;
33
- `;
34
-
35
- const tierDescriptionStyle = css`
36
- margin: 0;
37
- color: var(--pf-t--global--text--color--regular);
38
- `;
39
-
40
- const learnMoreLinkStyle = css`
41
- display: inline-flex;
42
- align-items: center;
43
- gap: var(--pf-t--global--spacer--xs);
44
- margin-top: var(--pf-t--global--spacer--400);
45
- `;
46
-
47
19
  const OsSupportTiersHelpBody: FC = () => (
48
- <div>
49
- <ul className={tierListStyle}>
50
- {ORDERED_SUPPORT_TIERS.map((tier) => (
51
- <li key={tier} className={tierItemStyle}>
52
- <Label
53
- className={tierBadgeStyle}
54
- color={getSupportTierBadgeColor(tier)}
55
- isCompact
56
- >
57
- {getSupportTierLegendLabel(tier)}
58
- </Label>
59
- <p className={tierDescriptionStyle}>
60
- {getSupportTierDefinition(tier)}
61
- </p>
62
- </li>
63
- ))}
64
- </ul>
65
- <a
66
- aria-label="Learn more about operating system support tiers"
67
- className={learnMoreLinkStyle}
68
- href={SUPPORT_TIER_LEARN_MORE_URL}
69
- target="_blank"
70
- rel="noopener noreferrer"
71
- >
72
- Learn more <ExternalLinkAltIcon />
73
- </a>
74
- </div>
20
+ <Stack hasGutter>
21
+ {ORDERED_SUPPORT_TIERS.map((tier) => (
22
+ <StackItem key={tier}>
23
+ <Label color={getSupportTierBadgeColor(tier)} isCompact>
24
+ {getSupportTierLegendLabel(tier)}
25
+ </Label>
26
+ <Content component="p">{getSupportTierDefinition(tier)}</Content>
27
+ </StackItem>
28
+ ))}
29
+ <StackItem>
30
+ <Button
31
+ variant="link"
32
+ isInline
33
+ component="a"
34
+ href={SUPPORT_TIER_LEARN_MORE_URL}
35
+ target="_blank"
36
+ rel="noopener noreferrer"
37
+ icon={<ExternalLinkAltIcon />}
38
+ iconPosition="end"
39
+ aria-label="Learn more about operating system support tiers"
40
+ >
41
+ Learn more
42
+ </Button>
43
+ </StackItem>
44
+ </Stack>
75
45
  );
76
46
 
77
47
  export const OsSupportTiersHelpPopover: FC = () => (
@@ -1,17 +1,11 @@
1
- import { css } from "@emotion/css";
2
1
  import { Content, Flex, FlexItem, Icon } from "@patternfly/react-core";
3
2
  import { InfoCircleIcon } from "@patternfly/react-icons";
4
3
  import type { FC } from "react";
5
4
 
6
- const noticeStyle = css`
7
- margin-bottom: var(--pf-t--global--spacer--200);
8
- `;
9
-
10
5
  export const OsUpgradeNotice: FC = () => (
11
6
  <Flex
12
7
  alignItems={{ default: "alignItemsCenter" }}
13
8
  spaceItems={{ default: "spaceItemsSm" }}
14
- className={noticeStyle}
15
9
  >
16
10
  <FlexItem>
17
11
  <Icon status="info">
@@ -19,7 +13,7 @@ export const OsUpgradeNotice: FC = () => (
19
13
  </Icon>
20
14
  </FlexItem>
21
15
  <FlexItem>
22
- <Content component="p" style={{ fontWeight: 500 }}>
16
+ <Content component="p">
23
17
  Some operating systems may need upgrades before migration
24
18
  </Content>
25
19
  </FlexItem>
@@ -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 || isExportMode) {
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
  />
@@ -0,0 +1,86 @@
1
+ import {
2
+ Card,
3
+ CardBody,
4
+ CardTitle,
5
+ Flex,
6
+ FlexItem,
7
+ } from "@patternfly/react-core";
8
+ import type { FC, ReactNode } from "react";
9
+ import {
10
+ MigrationDonutChart,
11
+ type MigrationDonutChartDatum,
12
+ type MigrationDonutChartLegendVariant,
13
+ } from "../charts/MigrationDonutChart.js";
14
+ import { CardEmptyState } from "./CardEmptyState.js";
15
+ import { ChartHeaderActions } from "./ChartDownloadButton.js";
16
+ import { ChartExportSurface } from "./ChartExportSurface.js";
17
+ import { dashboardStyles } from "./dashboardStyles.js";
18
+
19
+ export interface PowerStateCardProps {
20
+ id: string;
21
+ title: string;
22
+ icon: ReactNode;
23
+ emptyTitle: string;
24
+ slices: MigrationDonutChartDatum[];
25
+ legend: Record<string, string>;
26
+ total: number;
27
+ subTitle: string;
28
+ itemsPerRow?: number;
29
+ legendVariant?: MigrationDonutChartLegendVariant;
30
+ }
31
+
32
+ export const PowerStateCard: FC<PowerStateCardProps> = ({
33
+ id,
34
+ title,
35
+ icon,
36
+ emptyTitle,
37
+ slices,
38
+ legend,
39
+ total,
40
+ subTitle,
41
+ itemsPerRow = 2,
42
+ legendVariant = "html",
43
+ }) => (
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>
84
+ );
85
+
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";