@@ -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,30 @@ 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 (only when applying or modifying VAC, not removing)
98+ const isVacPending =
99+ ! vacErrorCondition &&
100+ volumeAttributesClassName &&
101+ volumeAttributesClassName !== currentVolumeAttributesClassName ;
102+
103+ return { vacErrorCondition, isVacPending } ;
104+ } ;
105+
79106export const PVCStatusComponent : React . FCC < PVCStatusProps > = ( { pvc } ) => {
80107 const { t } = useTranslation ( ) ;
81108 const [ pvcStatusExtensions , resolved ] = useResolvedExtensions < PVCStatus > ( isPVCStatus ) ;
@@ -249,6 +276,17 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
249276 const volumeMode = pvc ?. spec ?. volumeMode ;
250277 const conditions = pvc ?. status ?. conditions ;
251278
279+ // State to track dismissed alerts
280+ const [ isErrorAlertDismissed , setIsErrorAlertDismissed ] = React . useState ( false ) ;
281+ const [ isInfoAlertDismissed , setIsInfoAlertDismissed ] = React . useState ( false ) ;
282+
283+ // Reset alert dismiss states when PVC changes
284+ const pvcUid = pvc ?. metadata ?. uid ;
285+ React . useEffect ( ( ) => {
286+ setIsErrorAlertDismissed ( false ) ;
287+ setIsInfoAlertDismissed ( false ) ;
288+ } , [ pvcUid ] ) ;
289+
252290 const query =
253291 name && namespace
254292 ? `kubelet_volume_stats_used_bytes{persistentvolumeclaim='${ name } ',namespace='${ namespace } '}`
@@ -288,10 +326,53 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
288326 ( { properties : { alert : AlertComponent } , uid } ) => < AlertComponent key = { uid } pvc = { pvc } /> ,
289327 ) ;
290328
329+ // Get VAC modification state using helper function
330+ const { vacErrorCondition, isVacPending } = getVACAlertState ( pvc ) ;
331+
291332 return (
292333 < >
293334 < PaneBody >
294335 { alertComponents }
336+ { isVACSupported && vacErrorCondition && ! isErrorAlertDismissed && (
337+ < Alert
338+ isInline
339+ variant = "danger"
340+ title = { t ( 'public~VolumeAttributesClass modification failed' ) }
341+ className = "co-alert co-alert--margin-bottom-sm"
342+ actionClose = { < AlertActionCloseButton onClose = { ( ) => setIsErrorAlertDismissed ( true ) } /> }
343+ >
344+ { truncateMiddle (
345+ vacErrorCondition . message ||
346+ t ( 'public~Failed to modify VolumeAttributesClass for this PersistentVolumeClaim.' ) ,
347+ { length : 200 , truncateEnd : true } ,
348+ ) }
349+ </ Alert >
350+ ) }
351+ { isVACSupported && isVacPending && ! isInfoAlertDismissed && (
352+ < Alert
353+ isInline
354+ variant = "info"
355+ title = {
356+ volumeAttributesClassName && ! currentVolumeAttributesClassName
357+ ? t ( 'public~VolumeAttributesClass application pending' )
358+ : t ( 'public~VolumeAttributesClass modification in progress' )
359+ }
360+ className = "co-alert co-alert--margin-bottom-sm"
361+ actionClose = { < AlertActionCloseButton onClose = { ( ) => setIsInfoAlertDismissed ( true ) } /> }
362+ >
363+ { ! currentVolumeAttributesClassName
364+ ? t ( 'public~VolumeAttributesClass "{{target}}" is pending application.' , {
365+ target : volumeAttributesClassName ,
366+ } )
367+ : t (
368+ 'public~VolumeAttributesClass is being modified from "{{current}}" to "{{target}}".' ,
369+ {
370+ current : currentVolumeAttributesClassName ,
371+ target : volumeAttributesClassName ,
372+ } ,
373+ ) }
374+ </ Alert >
375+ ) }
295376 < SectionHeading text = { t ( 'public~PersistentVolumeClaim details' ) } />
296377 { totalCapacityMetric && ! loading && (
297378 < div className = "co-pvc-donut" >
@@ -383,19 +464,34 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
383464 ) }
384465 </ DescriptionListDescription >
385466 </ DescriptionListGroup >
386- { isVACSupported &&
387- ! ! volumeAttributesClassName &&
388- volumeAttributesClassName === currentVolumeAttributesClassName && (
389- < DescriptionListGroup >
390- < DescriptionListTerm > { t ( 'public~VolumeAttributesClass' ) } </ DescriptionListTerm >
391- < DescriptionListDescription >
467+ { isVACSupported && (
468+ < DescriptionListGroup >
469+ < DescriptionListTerm >
470+ { t ( 'public~Requested VolumeAttributesClass' ) }
471+ </ DescriptionListTerm >
472+ < DescriptionListDescription data-test-id = "pvc-requested-vac" >
473+ { volumeAttributesClassName ? (
392474 < ResourceLink
393475 kind = { referenceFor ( VolumeAttributesClassModel ) }
394476 name = { volumeAttributesClassName }
395477 />
396- </ DescriptionListDescription >
397- </ DescriptionListGroup >
398- ) }
478+ ) : (
479+ DASH
480+ ) }
481+ </ DescriptionListDescription >
482+ </ DescriptionListGroup >
483+ ) }
484+ { isVACSupported && ! ! currentVolumeAttributesClassName && (
485+ < DescriptionListGroup >
486+ < DescriptionListTerm > { t ( 'public~VolumeAttributesClass' ) } </ DescriptionListTerm >
487+ < DescriptionListDescription data-test-id = "pvc-current-vac" >
488+ < ResourceLink
489+ kind = { referenceFor ( VolumeAttributesClassModel ) }
490+ name = { currentVolumeAttributesClassName }
491+ />
492+ </ DescriptionListDescription >
493+ </ DescriptionListGroup >
494+ ) }
399495 { volumeName && canListPV && (
400496 < DescriptionListGroup >
401497 < DescriptionListTerm > { t ( 'public~PersistentVolumes' ) } </ DescriptionListTerm >
0 commit comments