Skip to content

Commit b8931c7

Browse files
committed
feat: enable clean code structure, enable secondary labels
1 parent c8183a0 commit b8931c7

File tree

20 files changed

+260
-191
lines changed

20 files changed

+260
-191
lines changed

src/components/BentoGrid/ComponentCard/BaseCard/BaseCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,4 @@ export const BaseCard = ({
8080
</Card>
8181
</div>
8282
);
83-
};
83+
};
Lines changed: 68 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useMemo } from 'react';
1+
import { useMemo, useState } from 'react';
22
import { useTranslation } from 'react-i18next';
33
import { BaseCard } from '../BaseCard/BaseCard';
44
import { MultiPercentageBar } from '../../MultiPercentageBar/MultiPercentageBar';
@@ -30,6 +30,11 @@ export const CrossplaneCard = ({
3030
size = 'medium',
3131
}: CrossplaneCardProps) => {
3232
const { t } = useTranslation();
33+
const [isProviderChartHovered, setIsProviderChartHovered] = useState(false);
34+
const [isHealthChartHovered, setIsHealthChartHovered] = useState(false);
35+
36+
// Show labels continuously only when explicitly expanded (coupled to expansion button)
37+
const shouldShowLabelsAlways = expanded;
3338

3439
// Fetch provider configs for distribution calculation
3540
const { data: providerConfigsList } = useProvidersConfigResource({
@@ -38,7 +43,7 @@ export const CrossplaneCard = ({
3843

3944
const crossplaneState = useMemo(
4045
() => calculateCrossplaneSegments(allItems, isLoading, error, enabled, t),
41-
[allItems, isLoading, error, enabled, t]
46+
[allItems, isLoading, error, enabled, t],
4247
);
4348

4449
// Calculate provider distribution for secondary bar
@@ -48,7 +53,6 @@ export const CrossplaneCard = ({
4853
);
4954

5055
const secondarySegments = providerDistribution.segments;
51-
const secondaryLabel = `${t('common.providers')} ${providerDistribution.totalProviders}`;
5256

5357
return (
5458
<BaseCard
@@ -58,9 +62,9 @@ export const CrossplaneCard = ({
5862
iconAlt="Crossplane"
5963
version={version}
6064
enabled={enabled}
61-
onClick={onClick}
6265
expanded={expanded}
6366
size={size}
67+
onClick={onClick}
6468
>
6569
<div
6670
className={
@@ -77,45 +81,16 @@ export const CrossplaneCard = ({
7781
: styles.progressBarContainerLarge
7882
}
7983
>
80-
<MultiPercentageBar
81-
segments={crossplaneState.segments}
82-
className={styles.progressBar}
83-
showOnlyNonZero={crossplaneState.showOnlyNonZero ?? true}
84-
isHealthy={crossplaneState.isHealthy}
85-
barWidth={size === 'small' ? '80%' : size === 'medium' ? '80%' : '90%'}
86-
barHeight={size === 'small' ? '10px' : size === 'medium' ? '16px' : '18px'}
87-
barMaxWidth={size === 'small' ? '400px' : size === 'medium' ? '500px' : 'none'}
88-
labelConfig={{
89-
position: 'above',
90-
displayMode: 'primary',
91-
showPercentage: size === 'medium' ? false : crossplaneState.showPercentage,
92-
showCount: false,
93-
primaryLabelText: size === 'medium' ? crossplaneState.label?.replace(/\s+\d+%?$/, '') || crossplaneState.label : crossplaneState.label,
94-
hideWhenSingleFull: false,
95-
fontWeight: 'bold',
96-
}}
97-
animationConfig={{
98-
enableWave: size !== 'medium',
99-
enableTransitions: size !== 'medium',
100-
duration: size === 'medium' ? 0 : 400,
101-
staggerDelay: size === 'medium' ? 0 : 100,
102-
}}
103-
showSegmentLabels={false}
104-
minSegmentWidthForLabel={12}
105-
/>
106-
</div>
107-
108-
{/* Secondary chart container - rendered below the primary chart */}
109-
{(size === 'medium' || size === 'large' || size === 'extra-large') && secondarySegments && (
110-
<div
111-
className={
112-
size === 'medium'
113-
? styles.progressBarContainerMedium
114-
: styles.progressBarContainerLarge
115-
}
84+
<div
85+
onMouseEnter={() => setIsProviderChartHovered(true)}
86+
onMouseLeave={() => setIsProviderChartHovered(false)}
11687
>
11788
<MultiPercentageBar
118-
segments={secondarySegments}
89+
segments={secondarySegments.map(segment => ({
90+
...segment,
91+
segmentLabel: `${segment.label} (${segment.count})`, // Provider name (count) - percentage handled by component
92+
segmentLabelColor: 'white'
93+
}))}
11994
className={styles.progressBar}
12095
showOnlyNonZero={true}
12196
barWidth={size === 'medium' ? '80%' : '90%'}
@@ -124,23 +99,70 @@ export const CrossplaneCard = ({
12499
labelConfig={{
125100
position: 'above',
126101
displayMode: 'primary',
127-
showPercentage: false,
128-
primaryLabelText: size === 'medium' ? secondaryLabel?.replace(/\s+\d+%?$/, '') || secondaryLabel : secondaryLabel,
102+
showPercentage: false, // Don't show percentage in primary label, only in segments
103+
primaryLabelText: t('common.providers'),
104+
primaryLabelValue: providerDistribution.totalProviders,
129105
hideWhenSingleFull: false,
130-
fontWeight: 'bold',
106+
fontWeight: 'bold',
131107
}}
132108
animationConfig={{
133109
enableWave: size !== 'medium',
134110
enableTransitions: size !== 'medium',
135111
duration: size === 'medium' ? 0 : 400,
136112
staggerDelay: size === 'medium' ? 0 : 100,
137113
}}
138-
showSegmentLabels={secondaryLabel?.includes('Providers')}
114+
showSegmentLabels={false}
115+
showSegmentLabelsOnHover={true} // Show segment labels only on hover
116+
showLabels={shouldShowLabelsAlways || isProviderChartHovered} // Show continuously when expanded/large or on hover
139117
minSegmentWidthForLabel={12}
140118
/>
141119
</div>
120+
</div>
121+
122+
{/* Secondary chart container - rendered below the primary chart */}
123+
{(size === 'medium' || size === 'large' || size === 'extra-large') && secondarySegments && (
124+
<div className={size === 'medium' ? styles.progressBarContainerMedium : styles.progressBarContainerLarge}>
125+
<div
126+
onMouseEnter={() => setIsHealthChartHovered(true)}
127+
onMouseLeave={() => setIsHealthChartHovered(false)}
128+
>
129+
<MultiPercentageBar
130+
segments={crossplaneState.segments.map(segment => ({
131+
...segment,
132+
segmentLabel: `${segment.label} (${segment.count})`, // Status (count) - percentage handled by component
133+
segmentLabelColor: 'white'
134+
}))}
135+
className={styles.progressBar}
136+
showOnlyNonZero={crossplaneState.showOnlyNonZero ?? true}
137+
isHealthy={crossplaneState.isHealthy}
138+
barWidth={size === 'medium' ? '80%' : '90%'}
139+
barHeight={size === 'medium' ? '16px' : '18px'}
140+
barMaxWidth={size === 'medium' ? '500px' : 'none'}
141+
labelConfig={{
142+
position: 'above',
143+
displayMode: 'primary',
144+
showPercentage: size === 'medium' ? false : crossplaneState.showPercentage, // Restore original logic
145+
showCount: false,
146+
primaryLabelText: 'Health',
147+
primaryLabelValue: undefined,
148+
hideWhenSingleFull: false,
149+
fontWeight: 'bold',
150+
}}
151+
animationConfig={{
152+
enableWave: size !== 'medium',
153+
enableTransitions: size !== 'medium',
154+
duration: size === 'medium' ? 0 : 400,
155+
staggerDelay: size === 'medium' ? 0 : 100,
156+
}}
157+
showSegmentLabels={false}
158+
showSegmentLabelsOnHover={true}
159+
showLabels={shouldShowLabelsAlways || isHealthChartHovered} // Show continuously when expanded/large or on hover
160+
minSegmentWidthForLabel={12}
161+
/>
162+
</div>
163+
</div>
142164
)}
143165
</div>
144166
</BaseCard>
145167
);
146-
};
168+
};

src/components/BentoGrid/ComponentCard/CrossplaneCard/crossplaneCalculations.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,18 @@ export const calculateCrossplaneSegments = (
9696
return {
9797
segments: [
9898
{ percentage: healthyPercentage, color: HINT_COLORS.healthy, label: t('common.healthy'), count: healthyCount },
99-
{ percentage: creatingPercentage, color: HINT_COLORS.creating, label: t('common.creating'), count: creatingCount },
100-
{ percentage: unhealthyPercentage, color: HINT_COLORS.unhealthy, label: t('common.unhealthy'), count: unhealthyCount },
99+
{
100+
percentage: creatingPercentage,
101+
color: HINT_COLORS.creating,
102+
label: t('common.creating'),
103+
count: creatingCount,
104+
},
105+
{
106+
percentage: unhealthyPercentage,
107+
color: HINT_COLORS.unhealthy,
108+
label: t('common.unhealthy'),
109+
count: unhealthyCount,
110+
},
101111
],
102112
label: t('Hints.CrossplaneHint.healthy'),
103113
showPercentage: true,
@@ -137,28 +147,26 @@ export const calculateCrossplaneHealthSegments = (
137147
}
138148

139149
// Count health states for all Crossplane managed resources
140-
const healthyCounts = allItems.filter(
141-
(item) => item?.status?.conditions?.some(
142-
(condition: any) => condition.type === 'Ready' && condition.status === 'True'
143-
)
150+
const healthyCounts = allItems.filter((item) =>
151+
item?.status?.conditions?.some((condition: any) => condition.type === 'Ready' && condition.status === 'True'),
144152
).length;
145153

146154
const total = allItems.length;
147155
const healthyPercentage = Math.round((healthyCounts / total) * 100);
148156
const remainingPercentage = 100 - healthyPercentage;
149-
157+
150158
const segments = [
151-
{
152-
percentage: healthyPercentage,
153-
color: '#38d4bc',
159+
{
160+
percentage: healthyPercentage,
161+
color: '#38d4bc',
154162
label: t('common.healthy'),
155-
count: healthyCounts
163+
count: healthyCounts,
156164
},
157-
remainingPercentage > 0 && {
158-
percentage: remainingPercentage,
159-
color: HINT_COLORS.inactive,
165+
remainingPercentage > 0 && {
166+
percentage: remainingPercentage,
167+
color: HINT_COLORS.inactive,
160168
label: t('common.remaining'),
161-
count: total - healthyCounts
169+
count: total - healthyCounts,
162170
},
163171
].filter(Boolean) as { percentage: number; color: string; label: string; count: number }[];
164172

@@ -208,4 +216,4 @@ export const calculateProviderDistribution = (items: ManagedResourceItem[], prov
208216
segments,
209217
totalProviders: segments.length,
210218
};
211-
};
219+
};

src/components/BentoGrid/ComponentCard/ESOCard/ESOCard.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const ESOCard = ({
3232

3333
const esoState = useMemo(
3434
() => calculateESOSegments(allItems, isLoading, error, enabled, t),
35-
[allItems, isLoading, error, enabled, t]
35+
[allItems, isLoading, error, enabled, t],
3636
);
3737

3838
return (
@@ -43,9 +43,9 @@ export const ESOCard = ({
4343
iconAlt="ESO"
4444
version={version}
4545
enabled={enabled}
46-
onClick={onClick}
4746
expanded={expanded}
4847
size={size}
48+
onClick={onClick}
4949
>
5050
<div className={styles.contentContainer}>
5151
<div
@@ -70,7 +70,8 @@ export const ESOCard = ({
7070
displayMode: 'primary',
7171
showPercentage: size === 'medium' ? false : esoState.showPercentage,
7272
showCount: false,
73-
primaryLabelText: size === 'medium' ? esoState.label?.replace(/\s+\d+%?$/, '') || esoState.label : esoState.label,
73+
primaryLabelText:
74+
size === 'medium' ? esoState.label?.replace(/\s+\d+%?$/, '') || esoState.label : esoState.label,
7475
hideWhenSingleFull: false,
7576
fontWeight: 'bold',
7677
}}
@@ -87,4 +88,4 @@ export const ESOCard = ({
8788
</div>
8889
</BaseCard>
8990
);
90-
};
91+
};

src/components/BentoGrid/ComponentCard/ESOCard/esoCalculations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,4 @@ export const calculateESOSegments = (
8080
isHealthy: false,
8181
showOnlyNonZero: true,
8282
};
83-
};
83+
};

src/components/BentoGrid/ComponentCard/FluxCard/FluxCard.tsx

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const FluxCard = ({
3636

3737
const fluxState = useMemo(
3838
() => calculateGitOpsSegments(allItems, isLoading, error, enabled, t),
39-
[allItems, isLoading, error, enabled, t]
39+
[allItems, isLoading, error, enabled, t],
4040
);
4141

4242
return (
@@ -47,9 +47,9 @@ export const FluxCard = ({
4747
iconAlt="Flux"
4848
version={version}
4949
enabled={enabled}
50-
onClick={onClick}
5150
expanded={expanded}
5251
size={size}
52+
onClick={onClick}
5353
>
5454
<div
5555
className={
@@ -79,7 +79,8 @@ export const FluxCard = ({
7979
displayMode: 'primary',
8080
showPercentage: size === 'medium' ? false : fluxState.showPercentage,
8181
showCount: false,
82-
primaryLabelText: size === 'medium' ? fluxState.label?.replace(/\s+\d+%?$/, '') || fluxState.label : fluxState.label,
82+
primaryLabelText:
83+
size === 'medium' ? fluxState.label?.replace(/\s+\d+%?$/, '') || fluxState.label : fluxState.label,
8384
hideWhenSingleFull: false,
8485
fontWeight: 'bold',
8586
}}
@@ -96,13 +97,7 @@ export const FluxCard = ({
9697

9798
{/* Secondary chart container - rendered below the primary chart */}
9899
{(size === 'medium' || size === 'large' || size === 'extra-large') && secondarySegments && (
99-
<div
100-
className={
101-
size === 'medium'
102-
? styles.progressBarContainerMedium
103-
: styles.progressBarContainerLarge
104-
}
105-
>
100+
<div className={size === 'medium' ? styles.progressBarContainerMedium : styles.progressBarContainerLarge}>
106101
<MultiPercentageBar
107102
segments={secondarySegments}
108103
className={styles.progressBar}
@@ -114,7 +109,8 @@ export const FluxCard = ({
114109
position: 'above',
115110
displayMode: 'primary',
116111
showPercentage: false,
117-
primaryLabelText: size === 'medium' ? secondaryLabel?.replace(/\s+\d+%?$/, '') || secondaryLabel : secondaryLabel,
112+
primaryLabelText:
113+
size === 'medium' ? secondaryLabel?.replace(/\s+\d+%?$/, '') || secondaryLabel : secondaryLabel,
118114
hideWhenSingleFull: false,
119115
fontWeight: 'bold',
120116
}}
@@ -132,4 +128,4 @@ export const FluxCard = ({
132128
</div>
133129
</BaseCard>
134130
);
135-
};
131+
};

0 commit comments

Comments
 (0)