@@ -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,36 @@ 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, pending state, requested and current VAC
86+ */
87+ const getVACModificationState = ( 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 errorCondition = conditions ?. find (
94+ ( condition ) => condition . type === 'ModifyVolumeError' && condition . status === 'True' ,
95+ ) ;
96+
97+ // Determine if modification is pending
98+ const isPending =
99+ ! errorCondition &&
100+ ( ( volumeAttributesClassName &&
101+ volumeAttributesClassName !== currentVolumeAttributesClassName ) ||
102+ ( ! volumeAttributesClassName && currentVolumeAttributesClassName ) ) ;
103+
104+ return {
105+ errorCondition,
106+ isPending,
107+ requested : volumeAttributesClassName ,
108+ current : currentVolumeAttributesClassName ,
109+ } ;
110+ } ;
111+
79112export const PVCStatusComponent : React . FCC < PVCStatusProps > = ( { pvc } ) => {
80113 const { t } = useTranslation ( ) ;
81114 const [ pvcStatusExtensions , resolved ] = useResolvedExtensions < PVCStatus > ( isPVCStatus ) ;
@@ -249,6 +282,17 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
249282 const volumeMode = pvc ?. spec ?. volumeMode ;
250283 const conditions = pvc ?. status ?. conditions ;
251284
285+ // State to track dismissed alerts
286+ const [ isErrorAlertDismissed , setIsErrorAlertDismissed ] = React . useState ( false ) ;
287+ const [ isInfoAlertDismissed , setIsInfoAlertDismissed ] = React . useState ( false ) ;
288+
289+ // Reset alert dismiss states when PVC changes
290+ const pvcUid = pvc ?. metadata ?. uid ;
291+ React . useEffect ( ( ) => {
292+ setIsErrorAlertDismissed ( false ) ;
293+ setIsInfoAlertDismissed ( false ) ;
294+ } , [ pvcUid ] ) ;
295+
252296 const query =
253297 name && namespace
254298 ? `kubelet_volume_stats_used_bytes{persistentvolumeclaim='${ name } ',namespace='${ namespace } '}`
@@ -288,10 +332,61 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
288332 ( { properties : { alert : AlertComponent } , uid } ) => < AlertComponent key = { uid } pvc = { pvc } /> ,
289333 ) ;
290334
335+ // Get VAC modification state using helper function
336+ const vacState = getVACModificationState ( pvc ) ;
337+ const {
338+ errorCondition : vacModifyFailedCondition ,
339+ isPending : isVACModificationPending ,
340+ } = vacState ;
341+
291342 return (
292343 < >
293344 < PaneBody >
294345 { alertComponents }
346+ { isVACSupported && vacModifyFailedCondition && ! isErrorAlertDismissed && (
347+ < Alert
348+ isInline
349+ variant = "danger"
350+ title = { t ( 'public~VolumeAttributesClass modification failed' ) }
351+ className = "co-alert co-alert--margin-bottom-sm"
352+ actionClose = { < AlertActionCloseButton onClose = { ( ) => setIsErrorAlertDismissed ( true ) } /> }
353+ >
354+ { truncateMiddle (
355+ vacModifyFailedCondition . message ||
356+ t ( 'public~Failed to modify VolumeAttributesClass for this PersistentVolumeClaim.' ) ,
357+ { length : 200 , truncateEnd : true } ,
358+ ) }
359+ </ Alert >
360+ ) }
361+ { isVACSupported && isVACModificationPending && ! isInfoAlertDismissed && (
362+ < Alert
363+ isInline
364+ variant = "info"
365+ title = {
366+ volumeAttributesClassName && ! currentVolumeAttributesClassName
367+ ? t ( 'public~VolumeAttributesClass application pending' )
368+ : t ( 'public~VolumeAttributesClass modification in progress' )
369+ }
370+ className = "co-alert co-alert--margin-bottom-sm"
371+ actionClose = { < AlertActionCloseButton onClose = { ( ) => setIsInfoAlertDismissed ( true ) } /> }
372+ >
373+ { volumeAttributesClassName
374+ ? ! currentVolumeAttributesClassName
375+ ? t ( 'public~VolumeAttributesClass "{{target}}" is pending application.' , {
376+ target : volumeAttributesClassName ,
377+ } )
378+ : t (
379+ 'public~VolumeAttributesClass is being modified from "{{current}}" to "{{target}}".' ,
380+ {
381+ current : currentVolumeAttributesClassName ,
382+ target : volumeAttributesClassName ,
383+ } ,
384+ )
385+ : t ( 'public~VolumeAttributesClass "{{current}}" is being removed.' , {
386+ current : currentVolumeAttributesClassName ,
387+ } ) }
388+ </ Alert >
389+ ) }
295390 < SectionHeading text = { t ( 'public~PersistentVolumeClaim details' ) } />
296391 { totalCapacityMetric && ! loading && (
297392 < div className = "co-pvc-donut" >
@@ -383,19 +478,34 @@ const PVCDetails: React.FCC<PVCDetailsProps> = ({ obj: pvc }) => {
383478 ) }
384479 </ DescriptionListDescription >
385480 </ DescriptionListGroup >
386- { isVACSupported &&
387- ! ! volumeAttributesClassName &&
388- volumeAttributesClassName === currentVolumeAttributesClassName && (
389- < DescriptionListGroup >
390- < DescriptionListTerm > { t ( 'public~VolumeAttributesClass' ) } </ DescriptionListTerm >
391- < DescriptionListDescription >
481+ { isVACSupported && (
482+ < DescriptionListGroup >
483+ < DescriptionListTerm >
484+ { t ( 'public~Requested VolumeAttributesClass' ) }
485+ </ DescriptionListTerm >
486+ < DescriptionListDescription data-test-id = "pvc-requested-vac" >
487+ { volumeAttributesClassName ? (
392488 < ResourceLink
393489 kind = { referenceFor ( VolumeAttributesClassModel ) }
394490 name = { volumeAttributesClassName }
395491 />
396- </ DescriptionListDescription >
397- </ DescriptionListGroup >
398- ) }
492+ ) : (
493+ DASH
494+ ) }
495+ </ DescriptionListDescription >
496+ </ DescriptionListGroup >
497+ ) }
498+ { isVACSupported && currentVolumeAttributesClassName && (
499+ < DescriptionListGroup >
500+ < DescriptionListTerm > { t ( 'public~VolumeAttributesClass' ) } </ DescriptionListTerm >
501+ < DescriptionListDescription data-test-id = "pvc-current-vac" >
502+ < ResourceLink
503+ kind = { referenceFor ( VolumeAttributesClassModel ) }
504+ name = { currentVolumeAttributesClassName }
505+ />
506+ </ DescriptionListDescription >
507+ </ DescriptionListGroup >
508+ ) }
399509 { volumeName && canListPV && (
400510 < DescriptionListGroup >
401511 < DescriptionListTerm > { t ( 'public~PersistentVolumes' ) } </ DescriptionListTerm >
0 commit comments