Skip to content

Commit e88abeb

Browse files
authored
Merge branch 'main' into feat/simplify-iframe-integrations
2 parents 90ede04 + 146de6b commit e88abeb

28 files changed

+2320
-15
lines changed

package-lock.json

Lines changed: 296 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"@ui5/webcomponents-fiori": "^2.7.2",
4141
"@ui5/webcomponents-icons": "^2.7.2",
4242
"@ui5/webcomponents-react": "^2.7.2",
43+
"@ui5/webcomponents-react-charts": "^2.13.1",
4344
"@xyflow/react": "^12.8.2",
4445
"clsx": "^2.1.1",
4546
"dagre": "^0.8.5",

public/locales/en.json

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@
172172
"defaultNamespaceInfo": "Leave empty to use <span>default</span> namespace",
173173
"serviceAccoutsGuide": "You can also use our <link1>Service Account Guide</link1> for more information."
174174
},
175+
175176
"ProjectsPage": {
176177
"header": "Your instances of <span>ManagedControlPlane</span>",
177178
"projectHeader": "Project:"
@@ -185,6 +186,7 @@
185186
"McpPage": {
186187
"accessError": "Managed Control Plane does not have access information yet",
187188
"componentsTitle": "Components",
189+
"overviewTitle": "Overview",
188190
"crossplaneTitle": "Crossplane",
189191
"gitOpsTitle": "GitOps",
190192
"landscapersTitle": "Landscapers",
@@ -334,7 +336,12 @@
334336
"synced": "Synced",
335337
"healthy": "Healthy",
336338
"installed": "Installed",
337-
"none": "None"
339+
"none": "None",
340+
"creating": "Creating",
341+
"unhealthy": "Unhealthy",
342+
"progress": "Managed",
343+
"remaining": "Remaining",
344+
"active": "Active"
338345
},
339346
"errors": {
340347
"installError": "Install error",
@@ -366,5 +373,52 @@
366373
"selectedComponents": "Selected Components",
367374
"pleaseSelectComponents": "Choose the components you want to add to your Managed Control Plane.",
368375
"cannotLoad": "Cannot load components list"
376+
},
377+
"Hints": {
378+
"CrossplaneHint": {
379+
"title": "Crossplane",
380+
"subtitle": "Managed Resources Readiness",
381+
"activeStatus": "Active v",
382+
"progressAvailable": "% Available",
383+
"noResources": "No Resources",
384+
"inactive": "Inactive",
385+
"activate": "Activate",
386+
"healthy": "Healthy",
387+
"hoverContent": {
388+
"totalResources": "Total Resources",
389+
"healthy": "Healthy",
390+
"creating": "Creating",
391+
"failing": "Failing"
392+
}
393+
},
394+
"GitOpsHint": {
395+
"title": "Flux",
396+
"subtitle": "GitOps Progress",
397+
"activeStatus": "Active v",
398+
"progressAvailable": "% Available",
399+
"noResources": "No Resources",
400+
"inactive": "Inactive",
401+
"activate": "Activate",
402+
"managed": "Managed",
403+
"hoverContent": {
404+
"totalResources": "Total Resources",
405+
"managed": "Managed",
406+
"unmanaged": "Unmanaged"
407+
}
408+
},
409+
"VaultHint": {
410+
"title": "Vault",
411+
"subtitle": "Rotating Secrets Progress",
412+
"activeStatus": "Active v",
413+
"progressAvailable": "% Available",
414+
"noResources": "No Resources",
415+
"inactive": "Coming soon...",
416+
"activate": "Activate"
417+
},
418+
"common": {
419+
"loading": "Loading...",
420+
"errorLoadingResources": "Error loading resources",
421+
"activate": "Activate"
422+
}
369423
}
370424
}

public/vault.png

24.9 KB
Loading

src/components/ControlPlanes/List/ControlPlaneListWorkspaceGridTile.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export function ControlPlaneListWorkspaceGridTile({ projectName, workspace }: Pr
120120
title={t('IllustratedBanner.titleMessage')}
121121
subtitle={t('IllustratedBanner.subtitleMessage')}
122122
illustrationName={IllustrationMessageType.NoData}
123+
compact
123124
help={{
124125
link: mcpCreationGuide,
125126
buttonText: t('IllustratedBanner.helpButton'),

src/components/Graphs/CustomNode.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const CustomNode: React.FC<CustomNodeProps> = ({ label, type, status, transition
2828
positiveText={t('common.healthy')}
2929
negativeText={t('errors.notHealthy')}
3030
message={statusMessage}
31+
hideOnHoverEffect={true}
3132
/>
3233
</div>
3334
<div className={styles.nodeTextContainer}>

src/components/Graphs/graphUtils.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,22 @@ export const resolveProviderType = (configName: string, providerConfigsList: Pro
2626
};
2727

2828
export const generateColorMap = (items: NodeData[], colorBy: string): Record<string, string> => {
29-
const colors = ['#E09D00', '#E6600D', '#AB218E', '#678BC7', '#1A9898', '#759421', '#925ACE', '#647987'];
29+
const colors = [
30+
'#FFC933', // MANGO 4
31+
'#FF8AF0', // PINK 4
32+
'#FEADC8', // RASPBERRY 4
33+
'#2CE0BF', // TEAL 4
34+
'#FF8CB2', // RED 4
35+
'#B894FF', // INDIGO 4
36+
'#049F9A', // TEAL 6
37+
'#FA4F96', // RASPBERRY 6
38+
'#F31DED', // PINK 6
39+
'#7858FF', // INDIGO 6
40+
'#07838F', // TEAL 7
41+
'#DF1278', // RASBERRY 7
42+
'#510080', // PINK 10
43+
'#5D36FF', // INDIGO 7
44+
];
3045

3146
const keys = (() => {
3247
if (colorBy === 'source') return Array.from(new Set(items.map((i) => i.providerType).filter(Boolean)));

src/components/Graphs/useGraph.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export function useGraph(colorBy: ColorBy, onYamlClick: (item: ManagedResourceIt
110110
const status = statusCond?.status === 'True' ? 'OK' : 'ERROR';
111111

112112
let fluxName: string | undefined;
113-
const labelsMap = (item.metadata as { labels?: Record<string, string> }).labels;
113+
const labelsMap = (item.metadata as unknown as { labels?: Record<string, string> }).labels;
114114
if (labelsMap) {
115115
const key = Object.keys(labelsMap).find((k) => k.endsWith('/name'));
116116
if (key) fluxName = labelsMap[key];
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* Card Hover Content Styles */
2+
.hoverContent {
3+
width: 100%;
4+
display: flex;
5+
flex-direction: column;
6+
align-items: center;
7+
margin: 1rem 0;
8+
overflow: visible;
9+
}
10+
11+
.chartContainer {
12+
width: 100%;
13+
height: 300px;
14+
display: flex;
15+
justify-content: center;
16+
align-items: center;
17+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import React, { useMemo } from 'react';
2+
import { RadarChart } from '@ui5/webcomponents-react-charts';
3+
import { LegendSection } from '../LegendSection/LegendSection';
4+
import { styles } from '../HintsCardsRow';
5+
import styles2 from './CardHoverContent.module.css';
6+
import cx from 'clsx';
7+
8+
export interface LegendItem {
9+
label: string;
10+
count: number;
11+
color: string;
12+
}
13+
14+
export interface RadarDataPoint {
15+
[key: string]: string | number;
16+
}
17+
18+
export interface RadarMeasure {
19+
accessor: string;
20+
color: string;
21+
hideDataLabel?: boolean;
22+
label: string;
23+
}
24+
25+
export interface RadarDimension {
26+
accessor: string;
27+
}
28+
29+
export interface HoverContentProps {
30+
enabled: boolean;
31+
totalCount: number;
32+
totalLabel: string;
33+
legendItems: LegendItem[];
34+
radarDataset: RadarDataPoint[];
35+
radarDimensions: RadarDimension[];
36+
radarMeasures: RadarMeasure[];
37+
isLoading?: boolean;
38+
}
39+
40+
// Helper function to truncate labels to max 13 characters
41+
const truncateLabel = (label: string, maxLength: number = 13): string => {
42+
if (label.length <= maxLength) {
43+
return label;
44+
}
45+
return label.substring(0, maxLength) + '...';
46+
};
47+
48+
export const HoverContent: React.FC<HoverContentProps> = ({
49+
enabled,
50+
totalCount,
51+
totalLabel,
52+
legendItems,
53+
radarDataset,
54+
radarDimensions,
55+
radarMeasures,
56+
isLoading = false,
57+
}) => {
58+
// Process the dataset to truncate labels
59+
const processedDataset = useMemo(() => {
60+
return radarDataset.map((dataPoint) => {
61+
const processedDataPoint = { ...dataPoint };
62+
63+
// Truncate labels for each dimension accessor
64+
radarDimensions.forEach((dimension) => {
65+
const value = dataPoint[dimension.accessor];
66+
if (typeof value === 'string') {
67+
processedDataPoint[dimension.accessor] = truncateLabel(value);
68+
}
69+
});
70+
71+
return processedDataPoint;
72+
});
73+
}, [radarDataset, radarDimensions]);
74+
75+
if (!enabled) {
76+
return null;
77+
}
78+
79+
return (
80+
<div className={cx(styles.hoverContent, styles2.hoverContent)}>
81+
<LegendSection title={`${totalCount} ${totalLabel}`} items={legendItems} />
82+
<div className={styles2.chartContainer}>
83+
{isLoading || radarDataset.length === 0 ? (
84+
<div className={cx(styles.hoverContentLoading)}>
85+
<RadarChart
86+
dataset={[]}
87+
dimensions={[
88+
{
89+
accessor: 'name',
90+
formatter: (value: string | number) => String(value || ''),
91+
},
92+
]}
93+
measures={[
94+
{
95+
accessor: 'users',
96+
formatter: (value: string | number) => String(value || ''),
97+
label: 'Users',
98+
},
99+
{
100+
accessor: 'sessions',
101+
formatter: (value: string | number) => String(value || ''),
102+
hideDataLabel: true,
103+
label: 'Active Sessions',
104+
},
105+
{
106+
accessor: 'volume',
107+
label: 'Vol.',
108+
},
109+
]}
110+
style={{ width: '100%', height: '100%', minWidth: 280, minHeight: 280 }}
111+
noLegend={true}
112+
onClick={() => {}}
113+
onDataPointClick={() => {}}
114+
onLegendClick={() => {}}
115+
/>
116+
</div>
117+
) : (
118+
<RadarChart
119+
dataset={processedDataset}
120+
dimensions={radarDimensions}
121+
measures={radarMeasures}
122+
style={{ width: '100%', height: '100%', minWidth: 280, minHeight: 280 }}
123+
noLegend={true}
124+
/>
125+
)}
126+
</div>
127+
</div>
128+
);
129+
};

0 commit comments

Comments
 (0)