@openshift-migration-advisor/shared-components 0.22.0-dd51551836b7 → 0.23.0-e2d66ca45d64
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 +6 -0
- package/dist/charts/MigrationDonutChart.d.ts +18 -1
- package/dist/charts/MigrationDonutChart.d.ts.map +1 -1
- package/dist/charts/MigrationDonutChart.js +103 -43
- package/dist/charts/index.d.ts +1 -1
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/forms/RadioButtonFormGroup.d.ts.map +1 -1
- package/dist/forms/RadioButtonFormGroup.js +2 -2
- package/dist/report/FeatureStatusBadge.d.ts +7 -0
- package/dist/report/FeatureStatusBadge.d.ts.map +1 -0
- package/dist/report/FeatureStatusBadge.js +13 -0
- package/dist/report/HostPowerStates.d.ts +9 -0
- package/dist/report/HostPowerStates.d.ts.map +1 -0
- package/dist/report/HostPowerStates.js +11 -0
- package/dist/report/InfrastructureSummary.d.ts +7 -0
- package/dist/report/InfrastructureSummary.d.ts.map +1 -0
- package/dist/report/InfrastructureSummary.js +5 -0
- package/dist/report/OSDistribution.d.ts.map +1 -1
- package/dist/report/OSDistribution.js +5 -13
- package/dist/report/OsSupportTiersHelpPopover.d.ts.map +1 -1
- package/dist/report/OsSupportTiersHelpPopover.js +2 -31
- package/dist/report/OsUpgradeNotice.d.ts.map +1 -1
- package/dist/report/OsUpgradeNotice.js +1 -5
- package/dist/report/PowerStateCard.d.ts +17 -0
- package/dist/report/PowerStateCard.d.ts.map +1 -0
- package/dist/report/PowerStateCard.js +7 -0
- package/dist/report/SupportTierBadge.d.ts.map +1 -1
- package/dist/report/SupportTierBadge.js +4 -2
- package/dist/report/VCenterClusterDetails.d.ts +10 -0
- package/dist/report/VCenterClusterDetails.d.ts.map +1 -0
- package/dist/report/VCenterClusterDetails.js +26 -0
- package/dist/report/VmPowerStates.d.ts +9 -0
- package/dist/report/VmPowerStates.d.ts.map +1 -0
- package/dist/report/VmPowerStates.js +11 -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/index.d.ts +10 -0
- package/dist/report/index.d.ts.map +1 -1
- package/dist/report/index.js +8 -0
- package/dist/report/infrastructureSummaryModel.d.ts +82 -0
- package/dist/report/infrastructureSummaryModel.d.ts.map +1 -0
- package/dist/report/infrastructureSummaryModel.js +139 -0
- package/dist/report/powerStates.d.ts +11 -0
- package/dist/report/powerStates.d.ts.map +1 -0
- package/dist/report/powerStates.js +113 -0
- package/package.json +1 -1
- package/src/charts/MigrationDonutChart.tsx +232 -111
- package/src/charts/index.ts +1 -0
- package/src/forms/RadioButtonFormGroup.tsx +10 -3
- package/src/report/FeatureStatusBadge.tsx +30 -0
- package/src/report/HostPowerStates.tsx +41 -0
- package/src/report/InfrastructureSummary.tsx +56 -0
- package/src/report/OSDistribution.tsx +60 -67
- package/src/report/OsSupportTiersHelpPopover.tsx +32 -61
- package/src/report/OsUpgradeNotice.tsx +1 -7
- package/src/report/PowerStateCard.tsx +73 -0
- package/src/report/SupportTierBadge.tsx +4 -2
- package/src/report/VCenterClusterDetails.tsx +211 -0
- package/src/report/VmPowerStates.tsx +41 -0
- package/src/report/__tests__/HostPowerStates.test.tsx +47 -0
- package/src/report/__tests__/InfrastructureSummary.test.tsx +148 -0
- package/src/report/__tests__/infrastructureSummaryModel.test.ts +224 -0
- package/src/report/__tests__/powerStates.test.ts +70 -0
- package/src/report/constants.ts +2 -0
- package/src/report/index.ts +56 -0
- package/src/report/infrastructureSummaryModel.ts +281 -0
- package/src/report/powerStates.ts +169 -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,
|
|
@@ -36,22 +38,9 @@ import {
|
|
|
36
38
|
useOsBarChartViewModel,
|
|
37
39
|
} from "./useOsBarChartViewModel.js";
|
|
38
40
|
|
|
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
41
|
const tableScrollStyle = css`
|
|
54
42
|
overflow: auto;
|
|
43
|
+
max-height: 350px;
|
|
55
44
|
`;
|
|
56
45
|
|
|
57
46
|
interface OSDistributionProps {
|
|
@@ -106,9 +95,9 @@ export const OSBarChart: FC<OSBarChartProps> = ({
|
|
|
106
95
|
return (
|
|
107
96
|
<>
|
|
108
97
|
{!isExportMode ? (
|
|
109
|
-
<Toolbar
|
|
98
|
+
<Toolbar hasNoPadding>
|
|
110
99
|
<ToolbarContent>
|
|
111
|
-
<ToolbarItem
|
|
100
|
+
<ToolbarItem>
|
|
112
101
|
<SearchInput
|
|
113
102
|
placeholder="Filter by OS"
|
|
114
103
|
value={vm.osFilter}
|
|
@@ -117,7 +106,7 @@ export const OSBarChart: FC<OSBarChartProps> = ({
|
|
|
117
106
|
aria-label="Filter operating systems by name"
|
|
118
107
|
/>
|
|
119
108
|
</ToolbarItem>
|
|
120
|
-
<ToolbarItem
|
|
109
|
+
<ToolbarItem>
|
|
121
110
|
<Select
|
|
122
111
|
isOpen={vm.isTierSelectOpen}
|
|
123
112
|
selected={vm.tierFilter}
|
|
@@ -128,7 +117,7 @@ export const OSBarChart: FC<OSBarChartProps> = ({
|
|
|
128
117
|
ref={toggleRef}
|
|
129
118
|
isExpanded={vm.isTierSelectOpen}
|
|
130
119
|
onClick={vm.toggleTierSelectOpen}
|
|
131
|
-
|
|
120
|
+
isFullWidth
|
|
132
121
|
>
|
|
133
122
|
{vm.tierFilterLabel}
|
|
134
123
|
</MenuToggle>
|
|
@@ -151,56 +140,60 @@ export const OSBarChart: FC<OSBarChartProps> = ({
|
|
|
151
140
|
</Toolbar>
|
|
152
141
|
) : null}
|
|
153
142
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
<
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
<
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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>
|
|
143
|
+
<Stack hasGutter>
|
|
144
|
+
{vm.showUpgradeNotice ? (
|
|
145
|
+
<StackItem>
|
|
146
|
+
<OsUpgradeNotice />
|
|
147
|
+
</StackItem>
|
|
148
|
+
) : null}
|
|
149
|
+
<StackItem>
|
|
150
|
+
<div
|
|
151
|
+
className={
|
|
152
|
+
isExportMode
|
|
153
|
+
? tableFullWidthStyle
|
|
154
|
+
: `${tableScrollStyle} ${tableFullWidthStyle}`
|
|
155
|
+
}
|
|
156
|
+
>
|
|
157
|
+
<Table aria-label="Operating systems" variant="compact">
|
|
158
|
+
<Thead>
|
|
159
|
+
<Tr>
|
|
160
|
+
<Th>OS</Th>
|
|
161
|
+
<Th>Tier</Th>
|
|
162
|
+
<Th>VMs</Th>
|
|
198
163
|
</Tr>
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
164
|
+
</Thead>
|
|
165
|
+
<Tbody>
|
|
166
|
+
{vm.showNoResults ? (
|
|
167
|
+
<Tr>
|
|
168
|
+
<Td colSpan={3}>
|
|
169
|
+
<EmptySearchResults title="No matching operating system found" />
|
|
170
|
+
</Td>
|
|
171
|
+
</Tr>
|
|
172
|
+
) : (
|
|
173
|
+
vm.filteredRows.map((row) => (
|
|
174
|
+
<Tr key={row.osName}>
|
|
175
|
+
<Td dataLabel="OS">
|
|
176
|
+
<OsNameCell
|
|
177
|
+
osName={row.osName}
|
|
178
|
+
upgradeRecommendation={row.upgradeRecommendation}
|
|
179
|
+
isExportMode={isExportMode}
|
|
180
|
+
/>
|
|
181
|
+
</Td>
|
|
182
|
+
<Td dataLabel="Tier">
|
|
183
|
+
<SupportTierBadge
|
|
184
|
+
tier={row.tier}
|
|
185
|
+
isExportMode={isExportMode}
|
|
186
|
+
/>
|
|
187
|
+
</Td>
|
|
188
|
+
<Td dataLabel="VMs">{row.count}</Td>
|
|
189
|
+
</Tr>
|
|
190
|
+
))
|
|
191
|
+
)}
|
|
192
|
+
</Tbody>
|
|
193
|
+
</Table>
|
|
194
|
+
</div>
|
|
195
|
+
</StackItem>
|
|
196
|
+
</Stack>
|
|
204
197
|
</>
|
|
205
198
|
);
|
|
206
199
|
};
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
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,66 +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
|
-
<
|
|
49
|
-
|
|
50
|
-
{
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
</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>
|
|
74
45
|
);
|
|
75
46
|
|
|
76
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"
|
|
16
|
+
<Content component="p">
|
|
23
17
|
Some operating systems may need upgrades before migration
|
|
24
18
|
</Content>
|
|
25
19
|
</FlexItem>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Card, CardBody, CardTitle } from "@patternfly/react-core";
|
|
2
|
+
import type { FC, ReactNode } from "react";
|
|
3
|
+
import {
|
|
4
|
+
MigrationDonutChart,
|
|
5
|
+
type MigrationDonutChartDatum,
|
|
6
|
+
type MigrationDonutChartLegendVariant,
|
|
7
|
+
} from "../charts/MigrationDonutChart.js";
|
|
8
|
+
import { CardEmptyState } from "./CardEmptyState.js";
|
|
9
|
+
import { dashboardStyles } from "./dashboardStyles.js";
|
|
10
|
+
|
|
11
|
+
export interface PowerStateCardProps {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
icon: ReactNode;
|
|
15
|
+
emptyTitle: string;
|
|
16
|
+
slices: MigrationDonutChartDatum[];
|
|
17
|
+
legend: Record<string, string>;
|
|
18
|
+
total: number;
|
|
19
|
+
subTitle: string;
|
|
20
|
+
isExportMode?: boolean;
|
|
21
|
+
itemsPerRow?: number;
|
|
22
|
+
legendVariant?: MigrationDonutChartLegendVariant;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const PowerStateCard: FC<PowerStateCardProps> = ({
|
|
26
|
+
id,
|
|
27
|
+
title,
|
|
28
|
+
icon,
|
|
29
|
+
emptyTitle,
|
|
30
|
+
slices,
|
|
31
|
+
legend,
|
|
32
|
+
total,
|
|
33
|
+
subTitle,
|
|
34
|
+
isExportMode = false,
|
|
35
|
+
itemsPerRow = 2,
|
|
36
|
+
legendVariant = "html",
|
|
37
|
+
}) => (
|
|
38
|
+
<Card
|
|
39
|
+
className={isExportMode ? dashboardStyles.cardPrint : dashboardStyles.card}
|
|
40
|
+
id={id}
|
|
41
|
+
>
|
|
42
|
+
<CardTitle>
|
|
43
|
+
{icon} {title}
|
|
44
|
+
</CardTitle>
|
|
45
|
+
<CardBody>
|
|
46
|
+
{total === 0 ? (
|
|
47
|
+
<CardEmptyState title={emptyTitle} />
|
|
48
|
+
) : (
|
|
49
|
+
<MigrationDonutChart
|
|
50
|
+
legendVariant={legendVariant}
|
|
51
|
+
data={slices}
|
|
52
|
+
legend={legend}
|
|
53
|
+
height={300}
|
|
54
|
+
width={420}
|
|
55
|
+
donutThickness={18}
|
|
56
|
+
padAngle={1}
|
|
57
|
+
title={`${total}`}
|
|
58
|
+
subTitle={subTitle}
|
|
59
|
+
subTitleColor="var(--pf-t--global--text--color--subtle)"
|
|
60
|
+
titleFontSize={34}
|
|
61
|
+
labelFontSize={16}
|
|
62
|
+
itemsPerRow={itemsPerRow}
|
|
63
|
+
marginLeft="0%"
|
|
64
|
+
tooltipLabelFormatter={({ datum, percent }) =>
|
|
65
|
+
`${datum.countDisplay}\n${percent.toFixed(1)}%`
|
|
66
|
+
}
|
|
67
|
+
/>
|
|
68
|
+
)}
|
|
69
|
+
</CardBody>
|
|
70
|
+
</Card>
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
PowerStateCard.displayName = "PowerStateCard";
|
|
@@ -9,13 +9,15 @@ import {
|
|
|
9
9
|
type SupportTier,
|
|
10
10
|
} from "./osSupportTier.js";
|
|
11
11
|
|
|
12
|
-
const exportBadgeStyle = css`
|
|
12
|
+
const exportBadgeStyle = (backgroundColor: string, color: string) => css`
|
|
13
13
|
display: inline-block;
|
|
14
14
|
padding: var(--pf-t--global--spacer--xs) var(--pf-t--global--spacer--sm);
|
|
15
15
|
border-radius: var(--pf-t--global--border--radius--pill);
|
|
16
16
|
font-size: var(--pf-t--global--font--size--body--sm);
|
|
17
17
|
line-height: var(--pf-t--global--font--line-height--body);
|
|
18
18
|
white-space: nowrap;
|
|
19
|
+
background-color: ${backgroundColor};
|
|
20
|
+
color: ${color};
|
|
19
21
|
`;
|
|
20
22
|
|
|
21
23
|
interface SupportTierBadgeProps {
|
|
@@ -27,7 +29,7 @@ const ExportSupportTierBadge: FC<{ tier: SupportTier }> = ({ tier }) => {
|
|
|
27
29
|
const { backgroundColor, color } = getSupportTierBadgeInlineStyle(tier);
|
|
28
30
|
|
|
29
31
|
return (
|
|
30
|
-
<span className={exportBadgeStyle
|
|
32
|
+
<span className={exportBadgeStyle(backgroundColor, color)}>
|
|
31
33
|
{getSupportTierLegendLabel(tier)}
|
|
32
34
|
</span>
|
|
33
35
|
);
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { css } from "@emotion/css";
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
CardBody,
|
|
5
|
+
CardTitle,
|
|
6
|
+
Content,
|
|
7
|
+
DescriptionList,
|
|
8
|
+
DescriptionListDescription,
|
|
9
|
+
DescriptionListGroup,
|
|
10
|
+
DescriptionListTerm,
|
|
11
|
+
Grid,
|
|
12
|
+
GridItem,
|
|
13
|
+
Label,
|
|
14
|
+
LabelGroup,
|
|
15
|
+
} from "@patternfly/react-core";
|
|
16
|
+
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
|
|
17
|
+
import type { FC } from "react";
|
|
18
|
+
import { FeatureStatusBadge } from "./FeatureStatusBadge.js";
|
|
19
|
+
import type {
|
|
20
|
+
ClusterDetailRow,
|
|
21
|
+
ClusterDetailsModel,
|
|
22
|
+
FeatureStatus,
|
|
23
|
+
} from "./infrastructureSummaryModel.js";
|
|
24
|
+
|
|
25
|
+
export interface VCenterClusterDetailsProps {
|
|
26
|
+
isAggregateView: boolean;
|
|
27
|
+
rows: ClusterDetailRow[];
|
|
28
|
+
details?: ClusterDetailsModel;
|
|
29
|
+
isExportMode?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const clusterDetailsTableScrollStyle = css`
|
|
33
|
+
max-height: 320px;
|
|
34
|
+
overflow: auto;
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
const FeatureList: FC<{
|
|
38
|
+
items: { label: string; status: FeatureStatus }[];
|
|
39
|
+
}> = ({ items }) => (
|
|
40
|
+
<DescriptionList isHorizontal isCompact>
|
|
41
|
+
{items.map((item) => (
|
|
42
|
+
<DescriptionListGroup key={item.label}>
|
|
43
|
+
<DescriptionListTerm>{item.label}</DescriptionListTerm>
|
|
44
|
+
<DescriptionListDescription>
|
|
45
|
+
<FeatureStatusBadge status={item.status} />
|
|
46
|
+
</DescriptionListDescription>
|
|
47
|
+
</DescriptionListGroup>
|
|
48
|
+
))}
|
|
49
|
+
</DescriptionList>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const AggregateClusterTable: FC<{
|
|
53
|
+
rows: ClusterDetailRow[];
|
|
54
|
+
}> = ({ rows }) => (
|
|
55
|
+
<Table
|
|
56
|
+
variant="compact"
|
|
57
|
+
borders={false}
|
|
58
|
+
isStickyHeader
|
|
59
|
+
data-testid="vcenter-cluster-details-table"
|
|
60
|
+
>
|
|
61
|
+
<Thead>
|
|
62
|
+
<Tr>
|
|
63
|
+
<Th>Cluster name</Th>
|
|
64
|
+
<Th>Hosts</Th>
|
|
65
|
+
<Th>VMs</Th>
|
|
66
|
+
<Th>vMotion</Th>
|
|
67
|
+
<Th>DRS</Th>
|
|
68
|
+
<Th>vSAN</Th>
|
|
69
|
+
</Tr>
|
|
70
|
+
</Thead>
|
|
71
|
+
<Tbody>
|
|
72
|
+
{rows.map((row) => (
|
|
73
|
+
<Tr key={row.id}>
|
|
74
|
+
<Td dataLabel="Cluster name">{row.name}</Td>
|
|
75
|
+
<Td dataLabel="Hosts">{row.hosts}</Td>
|
|
76
|
+
<Td dataLabel="VMs">{row.vms}</Td>
|
|
77
|
+
<Td dataLabel="vMotion">
|
|
78
|
+
<FeatureStatusBadge status={row.vmotion} />
|
|
79
|
+
</Td>
|
|
80
|
+
<Td dataLabel="DRS">
|
|
81
|
+
<FeatureStatusBadge status={row.drs} />
|
|
82
|
+
</Td>
|
|
83
|
+
<Td dataLabel="vSAN">
|
|
84
|
+
<FeatureStatusBadge status={row.vsan} />
|
|
85
|
+
</Td>
|
|
86
|
+
</Tr>
|
|
87
|
+
))}
|
|
88
|
+
</Tbody>
|
|
89
|
+
</Table>
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const AggregateCluster: FC<{
|
|
93
|
+
rows: ClusterDetailRow[];
|
|
94
|
+
isExportMode: boolean;
|
|
95
|
+
}> = ({ rows, isExportMode }) => {
|
|
96
|
+
if (rows.length === 0) {
|
|
97
|
+
return <Content component="p">No vSphere clusters detected</Content>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
className={isExportMode ? undefined : clusterDetailsTableScrollStyle}
|
|
103
|
+
data-scroll-constrained={isExportMode ? undefined : "true"}
|
|
104
|
+
>
|
|
105
|
+
<AggregateClusterTable rows={rows} />
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const DetailedClusterView: FC<{ details: ClusterDetailsModel }> = ({
|
|
111
|
+
details,
|
|
112
|
+
}) => (
|
|
113
|
+
<Grid hasGutter>
|
|
114
|
+
<GridItem>
|
|
115
|
+
<DescriptionList isAutoFit displaySize="lg">
|
|
116
|
+
<DescriptionListGroup>
|
|
117
|
+
<DescriptionListTerm>Hosts</DescriptionListTerm>
|
|
118
|
+
<DescriptionListDescription>
|
|
119
|
+
{details.hosts}
|
|
120
|
+
</DescriptionListDescription>
|
|
121
|
+
</DescriptionListGroup>
|
|
122
|
+
<DescriptionListGroup>
|
|
123
|
+
<DescriptionListTerm>VMs</DescriptionListTerm>
|
|
124
|
+
<DescriptionListDescription>{details.vms}</DescriptionListDescription>
|
|
125
|
+
</DescriptionListGroup>
|
|
126
|
+
<DescriptionListGroup>
|
|
127
|
+
<DescriptionListTerm>Networks detected</DescriptionListTerm>
|
|
128
|
+
<DescriptionListDescription>
|
|
129
|
+
{details.networksDetected}
|
|
130
|
+
</DescriptionListDescription>
|
|
131
|
+
</DescriptionListGroup>
|
|
132
|
+
</DescriptionList>
|
|
133
|
+
</GridItem>
|
|
134
|
+
<GridItem md={4}>
|
|
135
|
+
<Card isFullHeight>
|
|
136
|
+
<CardTitle>Core infrastructure</CardTitle>
|
|
137
|
+
<CardBody>
|
|
138
|
+
<FeatureList
|
|
139
|
+
items={[
|
|
140
|
+
{ label: "vMotion", status: details.vmotion },
|
|
141
|
+
{ label: "DRS", status: details.drs },
|
|
142
|
+
{ label: "HA", status: details.ha },
|
|
143
|
+
]}
|
|
144
|
+
/>
|
|
145
|
+
</CardBody>
|
|
146
|
+
</Card>
|
|
147
|
+
</GridItem>
|
|
148
|
+
<GridItem md={4}>
|
|
149
|
+
<Card isFullHeight>
|
|
150
|
+
<CardTitle>vSAN capabilities</CardTitle>
|
|
151
|
+
<CardBody>
|
|
152
|
+
<FeatureList items={[{ label: "vSAN", status: details.vsan }]} />
|
|
153
|
+
</CardBody>
|
|
154
|
+
</Card>
|
|
155
|
+
</GridItem>
|
|
156
|
+
<GridItem md={4}>
|
|
157
|
+
<Card isFullHeight>
|
|
158
|
+
<CardTitle>Network topology</CardTitle>
|
|
159
|
+
<CardBody>
|
|
160
|
+
{details.networks.length === 0 ? (
|
|
161
|
+
<Content component="p">No networks detected</Content>
|
|
162
|
+
) : (
|
|
163
|
+
<>
|
|
164
|
+
<Content component="p">
|
|
165
|
+
{details.networksDetected}{" "}
|
|
166
|
+
{details.networksDetected === 1
|
|
167
|
+
? "network detected"
|
|
168
|
+
: "networks detected"}
|
|
169
|
+
</Content>
|
|
170
|
+
<LabelGroup
|
|
171
|
+
isCompact
|
|
172
|
+
numLabels={details.networks.length}
|
|
173
|
+
aria-label="Detected networks"
|
|
174
|
+
>
|
|
175
|
+
{details.networks.map((network, index) => (
|
|
176
|
+
<Label
|
|
177
|
+
key={`${network.name}-${network.vlanId ?? index}`}
|
|
178
|
+
color="blue"
|
|
179
|
+
isCompact
|
|
180
|
+
>
|
|
181
|
+
{network.displayName}
|
|
182
|
+
</Label>
|
|
183
|
+
))}
|
|
184
|
+
</LabelGroup>
|
|
185
|
+
</>
|
|
186
|
+
)}
|
|
187
|
+
</CardBody>
|
|
188
|
+
</Card>
|
|
189
|
+
</GridItem>
|
|
190
|
+
</Grid>
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
export const VCenterClusterDetails: FC<VCenterClusterDetailsProps> = ({
|
|
194
|
+
isAggregateView,
|
|
195
|
+
rows,
|
|
196
|
+
details,
|
|
197
|
+
isExportMode = false,
|
|
198
|
+
}) => (
|
|
199
|
+
<Card isFullHeight id="vcenter-cluster-details">
|
|
200
|
+
<CardTitle>vCenter cluster details</CardTitle>
|
|
201
|
+
<CardBody>
|
|
202
|
+
{isAggregateView || !details ? (
|
|
203
|
+
<AggregateCluster rows={rows} isExportMode={isExportMode} />
|
|
204
|
+
) : (
|
|
205
|
+
<DetailedClusterView details={details} />
|
|
206
|
+
)}
|
|
207
|
+
</CardBody>
|
|
208
|
+
</Card>
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
VCenterClusterDetails.displayName = "VCenterClusterDetails";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { VirtualMachineIcon } from "@patternfly/react-icons";
|
|
2
|
+
import type { FC } from "react";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import type { MigrationDonutChartLegendVariant } from "../charts/MigrationDonutChart.js";
|
|
5
|
+
import { REPORT_CARD_EMPTY_STATE_TITLES } from "./constants.js";
|
|
6
|
+
import { PowerStateCard } from "./PowerStateCard.js";
|
|
7
|
+
import { buildVmPowerStateChart } from "./powerStates.js";
|
|
8
|
+
|
|
9
|
+
export interface VmPowerStatesProps {
|
|
10
|
+
powerStates?: Record<string, number>;
|
|
11
|
+
isExportMode?: boolean;
|
|
12
|
+
legendVariant?: MigrationDonutChartLegendVariant;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const VmPowerStates: FC<VmPowerStatesProps> = ({
|
|
16
|
+
powerStates,
|
|
17
|
+
isExportMode = false,
|
|
18
|
+
legendVariant,
|
|
19
|
+
}) => {
|
|
20
|
+
const chart = useMemo(
|
|
21
|
+
() => buildVmPowerStateChart(powerStates),
|
|
22
|
+
[powerStates],
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<PowerStateCard
|
|
27
|
+
id="vm-power-states"
|
|
28
|
+
title="VM power states"
|
|
29
|
+
icon={<VirtualMachineIcon />}
|
|
30
|
+
emptyTitle={REPORT_CARD_EMPTY_STATE_TITLES.vmPowerStates}
|
|
31
|
+
slices={chart.slices}
|
|
32
|
+
legend={chart.legend}
|
|
33
|
+
total={chart.total}
|
|
34
|
+
subTitle="VMs"
|
|
35
|
+
isExportMode={isExportMode}
|
|
36
|
+
legendVariant={legendVariant}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
VmPowerStates.displayName = "VmPowerStates";
|