1- import { useMemo } from 'react' ;
1+ import { useMemo , useState } from 'react' ;
22import { useTranslation } from 'react-i18next' ;
33import { BaseCard } from '../BaseCard/BaseCard' ;
44import { 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+ } ;
0 commit comments