@@ -4,6 +4,8 @@ import i18next, { TFunction } from 'i18next';
44import { useTranslation } from 'react-i18next' ;
55import { useDispatch , useSelector } from 'react-redux' ;
66import {
7+ Alert ,
8+ AlertActionCloseButton ,
79 DescriptionList ,
810 DescriptionListDescription ,
911 DescriptionListGroup ,
@@ -55,6 +57,7 @@ import { SectionHeading } from './utils/headings';
5557import { ResourceLink } from './utils/resource-link' ;
5658import { ResourceSummary } from './utils/details-page' ;
5759import { Selector } from './utils/selector' ;
60+ import { truncateMiddle } from './utils/truncate-middle' ;
5861import { humanizeBinaryBytes , convertToBaseValue } from './utils/units' ;
5962import { ResourceEventStream } from './events' ;
6063import { PVCMetrics , setPVCMetrics } from '@console/internal/actions/ui' ;
@@ -76,6 +79,31 @@ const tableColumnInfo = [
7679 { id : '' } ,
7780] ;
7881
82+ /**
83+ * Determines the VAC (VolumeAttributesClass) modification state for a PVC
84+ * @param pvc - The PersistentVolumeClaim resource
85+ * @returns Object containing error condition and pending state
86+ */
87+ const getVACAlertState = ( pvc : PersistentVolumeClaimKind ) => {
88+ const volumeAttributesClassName = pvc ?. spec ?. volumeAttributesClassName ;
89+ const currentVolumeAttributesClassName = pvc ?. status ?. currentVolumeAttributesClassName ;
90+ const conditions = pvc ?. status ?. conditions ;
91+
92+ // Check for explicit ModifyVolumeError condition
93+ const vacErrorCondition = conditions ?. find (
94+ ( condition ) => condition . type === 'ModifyVolumeError' && condition . status === 'True' ,
95+ ) ;
96+
97+ // Determine if modification is pending
98+ const isVacPending =
99+ ! vacErrorCondition &&
100+ ( ( volumeAttributesClassName &&
101+ volumeAttributesClassName !== currentVolumeAttributesClassName ) ||
102+ ( ! volumeAttributesClassName && currentVolumeAttributesClassName ) ) ;
103+
104+ return { vacErrorCondition, isVacPending } ;
105+ } ;
106+
79107export const PVCStatusComponent : React . FCC < PVCStatusProps > = ( { pvc } ) => {
80108 const { t } = useTranslation ( ) ;
81109 const [ pvcStatusExtensions , resolved ] = useResolvedExtensions < PVCStatus > ( isPVCStatus ) ;
@@ -249,6 +277,17 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
249277 const volumeMode = pvc ?. spec ?. volumeMode ;
250278 const conditions = pvc ?. status ?. conditions ;
251279
280+ // State to track dismissed alerts
281+ const [ isErrorAlertDismissed , setIsErrorAlertDismissed ] = React . useState ( false ) ;
282+ const [ isInfoAlertDismissed , setIsInfoAlertDismissed ] = React . useState ( false ) ;
283+
284+ // Reset alert dismiss states when PVC changes
285+ const pvcUid = pvc ?. metadata ?. uid ;
286+ React . useEffect ( ( ) => {
287+ setIsErrorAlertDismissed ( false ) ;
288+ setIsInfoAlertDismissed ( false ) ;
289+ } , [ pvcUid ] ) ;
290+
252291 const query =
253292 name && namespace
254293 ? `kubelet_volume_stats_used_bytes{persistentvolumeclaim='${ name } ',namespace='${ namespace } '}`
@@ -288,10 +327,57 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
288327 ( { properties : { alert : AlertComponent } , uid } ) => < AlertComponent key = { uid } pvc = { pvc } /> ,
289328 ) ;
290329
330+ // Get VAC modification state using helper function
331+ const { vacErrorCondition, isVacPending } = getVACAlertState ( pvc ) ;
332+
291333 return (
292334 < >
293335 < PaneBody >
294336 { alertComponents }
337+ { isVACSupported && vacErrorCondition && ! isErrorAlertDismissed && (
338+ < Alert
339+ isInline
340+ variant = "danger"
341+ title = { t ( 'public~VolumeAttributesClass modification failed' ) }
342+ className = "co-alert co-alert--margin-bottom-sm"
343+ actionClose = { < AlertActionCloseButton onClose = { ( ) => setIsErrorAlertDismissed ( true ) } /> }
344+ >
345+ { truncateMiddle (
346+ vacErrorCondition . message ||
347+ t ( 'public~Failed to modify VolumeAttributesClass for this PersistentVolumeClaim.' ) ,
348+ { length : 200 , truncateEnd : true } ,
349+ ) }
350+ </ Alert >
351+ ) }
352+ { isVACSupported && isVacPending && ! isInfoAlertDismissed && (
353+ < Alert
354+ isInline
355+ variant = "info"
356+ title = {
357+ volumeAttributesClassName && ! currentVolumeAttributesClassName
358+ ? t ( 'public~VolumeAttributesClass application pending' )
359+ : t ( 'public~VolumeAttributesClass modification in progress' )
360+ }
361+ className = "co-alert co-alert--margin-bottom-sm"
362+ actionClose = { < AlertActionCloseButton onClose = { ( ) => setIsInfoAlertDismissed ( true ) } /> }
363+ >
364+ { volumeAttributesClassName
365+ ? ! currentVolumeAttributesClassName
366+ ? t ( 'public~VolumeAttributesClass "{{target}}" is pending application.' , {
367+ target : volumeAttributesClassName ,
368+ } )
369+ : t (
370+ 'public~VolumeAttributesClass is being modified from "{{current}}" to "{{target}}".' ,
371+ {
372+ current : currentVolumeAttributesClassName ,
373+ target : volumeAttributesClassName ,
374+ } ,
375+ )
376+ : t ( 'public~VolumeAttributesClass "{{current}}" is being removed.' , {
377+ current : currentVolumeAttributesClassName ,
378+ } ) }
379+ </ Alert >
380+ ) }
295381 < SectionHeading text = { t ( 'public~PersistentVolumeClaim details' ) } />
296382 { totalCapacityMetric && ! loading && (
297383 < div className = "co-pvc-donut" >
@@ -383,19 +469,34 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
383469 ) }
384470 </ DescriptionListDescription >
385471 </ DescriptionListGroup >
386- { isVACSupported &&
387- ! ! volumeAttributesClassName &&
388- volumeAttributesClassName === currentVolumeAttributesClassName && (
389- < DescriptionListGroup >
390- < DescriptionListTerm > { t ( 'public~VolumeAttributesClass' ) } </ DescriptionListTerm >
391- < DescriptionListDescription >
472+ { isVACSupported && (
473+ < DescriptionListGroup >
474+ < DescriptionListTerm >
475+ { t ( 'public~Requested VolumeAttributesClass' ) }
476+ </ DescriptionListTerm >
477+ < DescriptionListDescription data-test-id = "pvc-requested-vac" >
478+ { volumeAttributesClassName ? (
392479 < ResourceLink
393480 kind = { referenceFor ( VolumeAttributesClassModel ) }
394481 name = { volumeAttributesClassName }
395482 />
396- </ DescriptionListDescription >
397- </ DescriptionListGroup >
398- ) }
483+ ) : (
484+ DASH
485+ ) }
486+ </ DescriptionListDescription >
487+ </ DescriptionListGroup >
488+ ) }
489+ { isVACSupported && ! ! currentVolumeAttributesClassName && (
490+ < DescriptionListGroup >
491+ < DescriptionListTerm > { t ( 'public~VolumeAttributesClass' ) } </ DescriptionListTerm >
492+ < DescriptionListDescription data-test-id = "pvc-current-vac" >
493+ < ResourceLink
494+ kind = { referenceFor ( VolumeAttributesClassModel ) }
495+ name = { currentVolumeAttributesClassName }
496+ />
497+ </ DescriptionListDescription >
498+ </ DescriptionListGroup >
499+ ) }
399500 { volumeName && canListPV && (
400501 < DescriptionListGroup >
401502 < DescriptionListTerm > { t ( 'public~PersistentVolumes' ) } </ DescriptionListTerm >
0 commit comments