Skip to content

Commit f19645c

Browse files
authored
Merge pull request #66 from ammont82/ECOPROJECT-3154-improve-os-histogram
ECOPROJECT-3154: Read new field osInfo for OS histogram
2 parents 633a1ee + aae33ae commit f19645c

File tree

3 files changed

+179
-92
lines changed

3 files changed

+179
-92
lines changed

src/components/MigrationChart.tsx

Lines changed: 113 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
FlexItem,
55
Text,
66
TextVariants,
7-
Tooltip
7+
Tooltip,
88
} from '@patternfly/react-core';
99
import { Table, Tbody, Td, Tr } from '@patternfly/react-table';
1010

@@ -21,40 +21,73 @@ interface MigrationChartProps {
2121
maxHeight?: string;
2222
}
2323

24-
type DLength = 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 60 | 70 | 80 | 90 | 100;
24+
type DLength =
25+
| 10
26+
| 15
27+
| 20
28+
| 25
29+
| 30
30+
| 35
31+
| 40
32+
| 45
33+
| 50
34+
| 60
35+
| 70
36+
| 80
37+
| 90
38+
| 100;
2539

2640
const legendColors = ['#28a745', '#f0ad4e', '#d9534f', '#C9190B'];
2741

28-
const MigrationChart: React.FC<MigrationChartProps> = ({ data, legend, dataLength=40,maxHeight='200px' }: MigrationChartProps) => {
42+
const MigrationChart: React.FC<MigrationChartProps> = ({
43+
data,
44+
legend,
45+
dataLength = 40,
46+
maxHeight = '200px',
47+
}: MigrationChartProps) => {
2948
const dynamicLegend = useMemo(() => {
30-
return data.reduce((acc, current) => {
31-
const key = `${current.legendCategory}`;
32-
if (!acc.seen.has(key)) {
33-
acc.seen.add(key);
34-
acc.result.push({[key]: legendColors[acc.seen.size - 1]});
35-
}
36-
return acc;
37-
}, { seen: new Set(), result: [] }).result;
49+
return data.reduce(
50+
(acc, current) => {
51+
const key = `${current.legendCategory}`;
52+
if (!acc.seen.has(key)) {
53+
acc.seen.add(key);
54+
acc.result.push({ [key]: legendColors[acc.seen.size - 1] });
55+
}
56+
return acc;
57+
},
58+
{ seen: new Set(), result: [] },
59+
).result;
3860
}, [data, legendColors]);
39-
61+
4062
const chartLegend = legend ? legend : Object.assign({}, ...dynamicLegend);
41-
const getColor = (name: string) : string => chartLegend[name];
63+
const getColor = (name: string): string => chartLegend[name];
4264

4365
return (
44-
<Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsLg' }}>
66+
<Flex
67+
direction={{ default: 'column' }}
68+
spaceItems={{ default: 'spaceItemsLg' }}
69+
>
4570
{/* Legend */}
4671
<FlexItem>
47-
<Flex spaceItems={{ default: 'spaceItemsLg' }} justifyContent={{ default: 'justifyContentFlexEnd' }}>
48-
{ Object.entries(chartLegend).map(([key, color]) => (
72+
<Flex
73+
spaceItems={{ default: 'spaceItemsLg' }}
74+
justifyContent={{ default: 'justifyContentFlexEnd' }}
75+
>
76+
{Object.entries(chartLegend).map(([key, color]) => (
4977
<FlexItem key={key}>
50-
<Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
78+
<Flex
79+
alignItems={{ default: 'alignItemsCenter' }}
80+
spaceItems={{ default: 'spaceItemsSm' }}
81+
>
5182
<FlexItem>
52-
<div style={{
53-
width: '12px',
54-
height: '12px',
55-
backgroundColor: color as string,
56-
borderRadius: '2px'
57-
}} />
83+
<div
84+
style={{
85+
width: '12px',
86+
height: '12px',
87+
backgroundColor: color as string,
88+
borderRadius: '2px',
89+
}}
90+
/>
5891
</FlexItem>
5992
<FlexItem>
6093
<Text component={TextVariants.small}>{key}</Text>
@@ -66,59 +99,77 @@ const MigrationChart: React.FC<MigrationChartProps> = ({ data, legend, dataLengt
6699
</FlexItem>
67100
{/* Chart Area */}
68101
<FlexItem>
69-
<Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsMd' }}>
70-
<div style={{maxHeight: maxHeight,overflowY: 'auto'}}>
102+
<Flex
103+
direction={{ default: 'column' }}
104+
spaceItems={{ default: 'spaceItemsMd' }}
105+
>
106+
<div style={{ maxHeight: maxHeight, overflowY: 'auto' }}>
71107
<Table variant="compact" borders={false}>
72108
<Tbody>
73109
{data.map((item, index) => (
74-
<Tr key={index}>
75-
<Td width={dataLength} style={{paddingLeft: '0px'}}>
76-
<Tooltip content={<div>{item.name}</div>} exitDelay={0}>
77-
<Text component={TextVariants.p}
78-
style={{fontSize: 'clamp(0.4rem, 0.7vw, 1.1rem)',
79-
overflow: 'hidden',
80-
textOverflow: 'ellipsis',
81-
wordBreak: 'break-word',
82-
display: '-webkit-box',
83-
WebkitLineClamp: 1, // Number of lines to show
84-
textTransform: 'capitalize',
85-
WebkitBoxOrient: 'vertical' }}>{item.name}</Text>
86-
</Tooltip>
87-
</Td>
88-
<Td>
110+
<Tr key={index}>
111+
<Td width={dataLength} style={{ paddingLeft: '0px' }}>
112+
<Tooltip content={<div>{item.name}</div>} exitDelay={0}>
113+
<Text
114+
component={TextVariants.p}
115+
style={{
116+
fontSize: 'clamp(0.4rem, 0.7vw, 1.1rem)',
117+
overflow: 'hidden',
118+
textOverflow: 'ellipsis',
119+
wordBreak: 'break-word',
120+
display: '-webkit-box',
121+
WebkitLineClamp: 1, // Number of lines to show
122+
textTransform: 'capitalize',
123+
WebkitBoxOrient: 'vertical',
124+
}}
125+
>
126+
{item.name}
127+
</Text>
128+
</Tooltip>
129+
</Td>
130+
<Td>
89131
{/* Visual Bar */}
90132
<div>
91-
<div style={{
92-
position: 'relative',
93-
height: '8px',
94-
backgroundColor: '#F5F5F5',
95-
overflow: 'hidden'
96-
}}>
97-
<div style={{
98-
height: '100%',
99-
width: `${item.count}%`,
100-
backgroundColor: `${getColor(item.legendCategory)}`,
101-
transition: 'width 0.3s ease'
102-
}} />
133+
<div
134+
style={{
135+
position: 'relative',
136+
height: '8px',
137+
backgroundColor: '#F5F5F5',
138+
overflow: 'hidden',
139+
}}
140+
>
141+
<div
142+
style={{
143+
height: '100%',
144+
width: `${item.count}%`,
145+
backgroundColor: `${getColor(
146+
item.legendCategory,
147+
)}`,
148+
transition: 'width 0.3s ease',
149+
}}
150+
/>
103151
</div>
104152
</div>
105-
</Td>
106-
<Td width={10} style={{paddingRight : '0px', textAlign: 'center'}}>
107-
<Text style={{fontSize: 'clamp(0.4rem, 0.7vw, 1.1rem)'}}>{item.count}</Text>
108-
</Td>
109-
</Tr>
110-
))}
153+
</Td>
154+
<Td
155+
width={10}
156+
style={{ paddingRight: '0px', textAlign: 'center' }}
157+
>
158+
<Text
159+
style={{ fontSize: 'clamp(0.4rem, 0.7vw, 1.1rem)' }}
160+
>
161+
{item.count}
162+
</Text>
163+
</Td>
164+
</Tr>
165+
))}
111166
</Tbody>
112167
</Table>
113168
</div>
114169
</Flex>
115170
</FlexItem>
116-
117-
118171
</Flex>
119172
);
120173
};
121174

122175
export default MigrationChart;
123-
124-

src/migration-wizard/steps/discovery/assessment-report/Dashboard.tsx

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
import React from 'react';
2-
import {
3-
PageSection,
4-
PageSectionVariants,
5-
Grid,
6-
GridItem,
7-
Gallery,
8-
GalleryItem,
9-
} from '@patternfly/react-core';
10-
import { InfrastructureOverview } from './InfastructureOverview';
2+
113
import {
124
Infra,
135
VMResourceBreakdown,
146
VMs,
157
} from '@migration-planner-ui/api-client/models';
16-
import { VMMigrationStatus } from './VMMigrationStatus';
8+
import {
9+
Gallery,
10+
GalleryItem,
11+
Grid,
12+
GridItem,
13+
PageSection,
14+
PageSectionVariants,
15+
} from '@patternfly/react-core';
16+
17+
import { Datastores } from './Datastores';
18+
import { InfrastructureOverview } from './InfastructureOverview';
1719
import { NetworkTopology } from './NetworkTopology';
18-
import { StorageOverview } from './StorageOverview';
1920
import { OSDistribution } from './OSDistribution';
20-
import { Datastores } from './Datastores';
21+
import { StorageOverview } from './StorageOverview';
22+
import { VMMigrationStatus } from './VMMigrationStatus';
2123

2224
import './Dashboard.css';
2325

@@ -36,6 +38,23 @@ export const Dashboard: React.FC<Props> = ({
3638
vms,
3739
isExportMode,
3840
}) => {
41+
// Transform osInfo to include both count and supported fields, fallback to os with supported=true if osInfo is undefined
42+
const osData = vms.osInfo
43+
? Object.entries(vms.osInfo).reduce((acc, [osName, osInfo]) => {
44+
acc[osName] = {
45+
count: osInfo.count,
46+
supported: osInfo.supported,
47+
};
48+
return acc;
49+
}, {} as { [osName: string]: { count: number; supported: boolean } })
50+
: Object.entries(vms.os).reduce((acc, [osName, count]) => {
51+
acc[osName] = {
52+
count: count,
53+
supported: true, // Default to supported when using fallback data
54+
};
55+
return acc;
56+
}, {} as { [osName: string]: { count: number; supported: boolean } });
57+
3958
return (
4059
<PageSection variant={PageSectionVariants.light}>
4160
<Grid hasGutter>
@@ -58,7 +77,7 @@ export const Dashboard: React.FC<Props> = ({
5877
/>
5978
</GalleryItem>
6079
<GalleryItem>
61-
<OSDistribution osData={vms.os} isExportMode={isExportMode}/>
80+
<OSDistribution osData={osData} isExportMode={isExportMode} />
6281
</GalleryItem>
6382
</Gallery>
6483
</GridItem>
@@ -73,18 +92,20 @@ export const Dashboard: React.FC<Props> = ({
7392
/>
7493
</GalleryItem>
7594
<GalleryItem>
76-
<NetworkTopology networks={infra.networks} isExportMode={isExportMode}/>
77-
95+
<NetworkTopology
96+
networks={infra.networks}
97+
isExportMode={isExportMode}
98+
/>
7899
</GalleryItem>
79100
</Gallery>
80101
</GridItem>
81102
<GridItem span={12}>
82103
<Gallery hasGutter minWidths={{ default: '80%' }}>
83104
<GalleryItem>
84-
<Datastores
85-
datastores={infra.datastores}
86-
isExportMode={isExportMode}
87-
/>
105+
<Datastores
106+
datastores={infra.datastores}
107+
isExportMode={isExportMode}
108+
/>
88109
</GalleryItem>
89110
</Gallery>
90111
</GridItem>
Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import React from 'react';
2+
23
import { Card, CardBody, CardTitle } from '@patternfly/react-core';
4+
35
import MigrationChart from '../../../../components/MigrationChart';
46

57
interface OSDistributionProps {
68
osData: {
7-
[osName: string]: number;
9+
[osName: string]: {
10+
count: number;
11+
supported: boolean;
12+
};
813
};
914
isExportMode?: boolean;
1015
}
@@ -13,23 +18,20 @@ export const OSDistribution: React.FC<OSDistributionProps> = ({
1318
osData,
1419
isExportMode = false,
1520
}) => {
16-
1721
return (
1822
<Card className={isExportMode ? 'dashboard-card-print' : 'dashboard-card'}>
1923
<CardTitle>
2024
<i className="fas fa-database" /> Operating Systems
2125
</CardTitle>
2226
<CardBody>
23-
24-
<OSBarChart osData={osData} isExportMode={isExportMode} />
25-
27+
<OSBarChart osData={osData} isExportMode={isExportMode} />
2628
</CardBody>
2729
</Card>
2830
);
2931
};
3032

3133
interface OSBarChartProps {
32-
osData: { [osName: string]: number };
34+
osData: { [osName: string]: { count: number; supported: boolean } };
3335
isExportMode?: boolean;
3436
}
3537

@@ -39,13 +41,26 @@ export const OSBarChart: React.FC<OSBarChartProps> = ({
3941
}) => {
4042
const dataEntries = Object.entries(osData).filter(([os]) => os.trim() !== '');
4143

42-
const sorted = dataEntries.sort(([, a], [, b]) => b - a);
44+
const sorted = dataEntries.sort(([, a], [, b]) => b.count - a.count);
4345

44-
const chartData = sorted.map(([os, count]) => ({
46+
const chartData = sorted.map(([os, osInfo]) => ({
4547
name: os,
46-
count: count,
47-
legendCategory: `Supported`, // You may want to add logic to determine if an OS is supported
48+
count: osInfo.count,
49+
legendCategory: osInfo.supported ? 'Supported' : 'Not Supported',
4850
}));
51+
52+
// Define custom colors: green for supported, red for not supported
53+
const customLegend = {
54+
Supported: '#28a745', // Green
55+
'Not Supported': '#d9534f', // Red
56+
};
57+
4958
const tableHeight = isExportMode ? '100%' : '200px';
50-
return <MigrationChart data={chartData} maxHeight={tableHeight} />;
59+
return (
60+
<MigrationChart
61+
data={chartData}
62+
legend={customLegend}
63+
maxHeight={tableHeight}
64+
/>
65+
);
5166
};

0 commit comments

Comments
 (0)