Skip to content

Commit 30f2e99

Browse files
committed
Improve VAC field on PVC details page
1 parent 335ed77 commit 30f2e99

File tree

1 file changed

+119
-9
lines changed

1 file changed

+119
-9
lines changed

frontend/public/components/persistent-volume-claim.tsx

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import i18next, { TFunction } from 'i18next';
44
import { useTranslation } from 'react-i18next';
55
import { useDispatch, useSelector } from 'react-redux';
66
import {
7+
Alert,
8+
AlertActionCloseButton,
79
DescriptionList,
810
DescriptionListDescription,
911
DescriptionListGroup,
@@ -55,6 +57,7 @@ import { SectionHeading } from './utils/headings';
5557
import { ResourceLink } from './utils/resource-link';
5658
import { ResourceSummary } from './utils/details-page';
5759
import { Selector } from './utils/selector';
60+
import { truncateMiddle } from './utils/truncate-middle';
5861
import { humanizeBinaryBytes, convertToBaseValue } from './utils/units';
5962
import { ResourceEventStream } from './events';
6063
import { 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+
79112
export 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

Comments
 (0)