diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Database/RetentionPeriod/RetentionPeriod.component.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Database/RetentionPeriod/RetentionPeriod.component.test.tsx index 613f9732fdf..69279fdf337 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Database/RetentionPeriod/RetentionPeriod.component.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Database/RetentionPeriod/RetentionPeriod.component.test.tsx @@ -143,6 +143,41 @@ describe('Test Retention Period Component', () => { expect(mockOnUpdate).toHaveBeenCalledWith('69 days and 16 hours'); }); + it('Should render correctly with ISO 8601 duration P0Y0M4D', () => { + render( + + ); + + expect(screen.getByText('4 days')).toBeInTheDocument(); + }); + + it('Should render correctly with ISO 8601 duration P0Y0M4W', () => { + render( + + ); + + expect(screen.getByText('4 weeks')).toBeInTheDocument(); + }); + + it('Should render correctly with ISO 8601 duration P0Y1M1DT1H30M', () => { + render( + + ); + + expect( + screen.getByText('2 years 1 month 1 day 1 hour 30 minutes') + ).toBeInTheDocument(); + }); + it('Should not render Retention Period Component if has no permission', () => { render( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Database/RetentionPeriod/RetentionPeriod.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Database/RetentionPeriod/RetentionPeriod.component.tsx index bc39d633430..83a1699ef05 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Database/RetentionPeriod/RetentionPeriod.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Database/RetentionPeriod/RetentionPeriod.component.tsx @@ -22,6 +22,7 @@ import { } from 'antd'; import { useForm } from 'antd/lib/form/Form'; import { AxiosError } from 'axios'; +import { Duration } from 'luxon'; import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg'; @@ -34,6 +35,58 @@ import { showErrorToast } from '../../../utils/ToastUtils'; import { ExtraInfoLabel } from '../../DataAssets/DataAssetsHeader/DataAssetsHeader.component'; import { RetentionPeriodProps } from './RetentionPeriod.interface'; +// Helper function to detect and format ISO 8601 duration +const formatRetentionPeriod = (retentionPeriod: string | undefined) => { + if (!retentionPeriod) { + return NO_DATA_PLACEHOLDER; + } + + const isoDurationRegex = + /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$/; + // Check if the string matches the ISO 8601 duration format + if (isoDurationRegex.test(retentionPeriod)) { + const duration = Duration.fromISO(retentionPeriod); + + const years = duration.years + ? `${duration.years} year${duration.years > 1 ? 's' : ''}` + : ''; + const months = duration.months + ? `${duration.months} month${duration.months > 1 ? 's' : ''}` + : ''; + const weeks = duration.weeks + ? `${duration.weeks} week${duration.weeks > 1 ? 's' : ''}` + : ''; + const days = duration.days + ? `${duration.days} day${duration.days > 1 ? 's' : ''}` + : ''; + const hours = duration.hours + ? `${duration.hours} hour${duration.hours > 1 ? 's' : ''}` + : ''; + const minutes = duration.minutes + ? `${duration.minutes} minute${duration.minutes > 1 ? 's' : ''}` + : ''; + const seconds = duration.seconds + ? `${duration.seconds} second${duration.seconds > 1 ? 's' : ''}` + : ''; + + const formattedDuration = [ + years, + months, + weeks, + days, + hours, + minutes, + seconds, + ] + .filter(Boolean) + .join(' '); + + return formattedDuration || NO_DATA_PLACEHOLDER; + } + + // If it's not ISO, return the plain string + return retentionPeriod; +}; const RetentionPeriod = ({ retentionPeriod, onUpdate, @@ -67,7 +120,7 @@ const RetentionPeriod = ({ {hasPermission && (