diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.test.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.test.tsx index 224ecc4fc7..ed6280b56c 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.test.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.test.tsx @@ -4,17 +4,19 @@ import { render } from 'utils/testRenderer'; import userEvent from '@testing-library/user-event'; import { vi } from 'vitest'; import type { LifecycleStage } from './LifecycleStage'; +import { DELETE_FEATURE } from 'component/providers/AccessProvider/permissions'; const currentTime = '2024-04-25T08:05:00.000Z'; const twoMinutesAgo = '2024-04-25T08:03:00.000Z'; const oneHourAgo = '2024-04-25T07:05:00.000Z'; const twoHoursAgo = '2024-04-25T06:05:00.000Z'; -const renderOpenTooltip = (stage: LifecycleStage) => { +const renderOpenTooltip = (stage: LifecycleStage, onArchive = () => {}) => { render( - + child , + { permissions: [{ permission: DELETE_FEATURE }] }, ); const child = screen.getByText('child'); @@ -89,14 +91,25 @@ test('render completed stage with still active', async () => { test('render completed stage safe to archive', async () => { vi.setSystemTime(currentTime); const enteredStageAt = twoMinutesAgo; + let onArchiveInvoked = false; + const onArchive = () => { + onArchiveInvoked = true; + }; - renderOpenTooltip({ - name: 'completed', - status: 'kept', - environments: [], - enteredStageAt, - }); + renderOpenTooltip( + { + name: 'completed', + status: 'kept', + environments: [], + enteredStageAt, + }, + onArchive, + ); await screen.findByText('completed'); - await screen.findByText('Archive feature'); + const button = await screen.findByText('Archive feature'); + + button.click(); + + expect(onArchiveInvoked).toBe(true); }); diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx index 38505bba8a..ddc4d447bf 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx @@ -287,7 +287,7 @@ const LiveStageDescription: FC = ({ children }) => { ); }; -const SafeToArchive: FC = () => { +const SafeToArchive: FC<{ onArchive: () => void }> = ({ onArchive }) => { return ( <> Safe to archive @@ -301,6 +301,7 @@ const SafeToArchive: FC = () => { permission={DELETE_FEATURE} size='small' sx={{ mb: 2 }} + onClick={onArchive} > Archive feature @@ -322,12 +323,13 @@ const ActivelyUsed: FC = ({ children }) => { }; const CompletedStageDescription: FC<{ + onArchive: () => void; environments: Array<{ name: string; lastSeenAt: string }>; -}> = ({ children, environments }) => { +}> = ({ children, environments, onArchive }) => { return ( } + show={} elseShow={{children}} /> ); @@ -348,7 +350,8 @@ const FormatElapsedTime: FC<{ time: string }> = ({ time }) => { export const FeatureLifecycleTooltip: FC<{ children: React.ReactElement; stage: LifecycleStage; -}> = ({ children, stage }) => ( + onArchive: () => void; +}> = ({ children, stage, onArchive }) => ( diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewMetaData/FeatureOverviewMetaData.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewMetaData/FeatureOverviewMetaData.tsx index 831261ac29..bcbc56fa6f 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewMetaData/FeatureOverviewMetaData.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewMetaData/FeatureOverviewMetaData.tsx @@ -1,5 +1,5 @@ import { capitalize, styled } from '@mui/material'; -import { Link } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; import { useFeature } from 'hooks/api/getters/useFeature/useFeature'; import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; @@ -10,6 +10,9 @@ import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { useUiFlag } from 'hooks/useUiFlag'; import { FeatureLifecycleTooltip } from '../FeatureLifecycle/FeatureLifecycleTooltip'; import { FeatureLifecycleStageIcon } from '../FeatureLifecycle/FeatureLifecycleStageIcon'; +import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog'; +import { useState } from 'react'; +import { FeatureArchiveNotAllowedDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveNotAllowedDialog'; import { populateCurrentStage } from '../FeatureLifecycle/populateCurrentStage'; const StyledContainer = styled('div')(({ theme }) => ({ @@ -79,6 +82,8 @@ const FeatureOverviewMetaData = () => { const { feature } = useFeature(projectId, featureId); const { project, description, type } = feature; const featureLifecycleEnabled = useUiFlag('featureLifecycle'); + const navigate = useNavigate(); + const [showDelDialog, setShowDelDialog] = useState(false); const IconComponent = getFeatureTypeIcons(type); @@ -108,20 +113,20 @@ const FeatureOverviewMetaData = () => { {project} Lifecycle: - - {currentStage && ( - - - - )} + setShowDelDialog(true)} + > + + } /> @@ -170,6 +175,28 @@ const FeatureOverviewMetaData = () => { /> + 0} + show={ + setShowDelDialog(false)} + /> + } + elseShow={ + { + navigate(`/projects/${projectId}`); + }} + onClose={() => setShowDelDialog(false)} + projectId={projectId} + featureIds={[featureId]} + /> + } + /> ); };