Skip to content

Commit

Permalink
feat: rename lifecycle stages (#9102)
Browse files Browse the repository at this point in the history
Name names for "lifecycle" stages, and aligning frontend types.
  • Loading branch information
Tymek authored Jan 16, 2025
1 parent 846dae6 commit 50ab2c9
Show file tree
Hide file tree
Showing 9 changed files with 651 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,39 @@ import { ReactComponent as Stage2 } from 'assets/icons/lifecycle/stage-2.svg';
import { ReactComponent as Stage3 } from 'assets/icons/lifecycle/stage-3.svg';
import { ReactComponent as Stage4 } from 'assets/icons/lifecycle/stage-4.svg';
import { ReactComponent as Stage5 } from 'assets/icons/lifecycle/stage-5.svg';
import type { LifecycleStage } from './LifecycleStage';
import type { LifecycleStage } from '../../feature/FeatureView/FeatureOverview/FeatureLifecycle/LifecycleStage';
import { useUiFlag } from 'hooks/useUiFlag';

export const FeatureLifecycleStageIcon: FC<{
stage: Pick<LifecycleStage, 'name'>;
}> = ({ stage }) => {
}> = ({ stage, ...props }) => {
const newIcons = useUiFlag('lifecycleImprovements');

if (stage.name === 'archived') {
return newIcons ? <Stage5 /> : <ArchivedStageIcon />;
return newIcons ? (
<Stage5 {...props} />
) : (
<ArchivedStageIcon {...props} />
);
} else if (stage.name === 'pre-live') {
return newIcons ? <Stage2 /> : <PreLiveStageIcon />;
return newIcons ? (
<Stage2 {...props} />
) : (
<PreLiveStageIcon {...props} />
);
} else if (stage.name === 'live') {
return newIcons ? <Stage3 /> : <LiveStageIcon />;
return newIcons ? <Stage3 {...props} /> : <LiveStageIcon {...props} />;
} else if (stage.name === 'completed') {
return newIcons ? <Stage4 /> : <CompletedStageIcon />;
return newIcons ? (
<Stage4 {...props} />
) : (
<CompletedStageIcon {...props} />
);
} else {
return newIcons ? <Stage1 /> : <InitialStageIcon />;
return newIcons ? (
<Stage1 {...props} />
) : (
<InitialStageIcon {...props} />
);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Lifecycle } from 'interfaces/featureToggle';

export const getFeatureLifecycleName = (stage: Lifecycle['stage']): string => {
if (stage === 'initial') {
return 'Define';
}
if (stage === 'pre-live') {
return 'Develop';
}
if (stage === 'live') {
return 'Production';
}
if (stage === 'completed') {
return 'Cleanup';
}
if (stage === 'archived') {
return 'Archived';
}

return stage;
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { FeatureLifecycleStageIcon } from './FeatureLifecycleStageIcon';
import { FeatureLifecycleStageIcon } from 'component/common/FeatureLifecycle/FeatureLifecycleStageIcon';
import { FeatureLifecycleTooltip as LegacyFeatureLifecycleTooltip } from './LegacyFeatureLifecycleTooltip';
import { FeatureLifecycleTooltip } from './FeatureLifecycleTooltip';
import useFeatureLifecycleApi from 'hooks/api/actions/useFeatureLifecycleApi/useFeatureLifecycleApi';
import { populateCurrentStage } from './populateCurrentStage';
import type { FC } from 'react';
import type { Lifecycle } from 'interfaces/featureToggle';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { useUiFlag } from 'hooks/useUiFlag';

export interface LifecycleFeature {
lifecycle?: Lifecycle;
Expand All @@ -25,10 +27,9 @@ export const FeatureLifecycle: FC<{
feature: LifecycleFeature;
}> = ({ feature, onComplete, onUncomplete, onArchive }) => {
const currentStage = populateCurrentStage(feature);

const { markFeatureUncompleted, loading } = useFeatureLifecycleApi();

const { trackEvent } = usePlausibleTracker();
const isLifecycleImprovementsEnabled = useUiFlag('lifecycleImprovements');

const onUncompleteHandler = async () => {
await markFeatureUncompleted(feature.name, feature.project);
Expand All @@ -40,16 +41,31 @@ export const FeatureLifecycle: FC<{
});
};

if (isLifecycleImprovementsEnabled) {
return currentStage ? (
<FeatureLifecycleTooltip
stage={currentStage!}
project={feature.project}
onArchive={onArchive}
onComplete={onComplete}
onUncomplete={onUncompleteHandler}
loading={loading}
>
<FeatureLifecycleStageIcon stage={currentStage} />
</FeatureLifecycleTooltip>
) : null;
}

return currentStage ? (
<FeatureLifecycleTooltip
<LegacyFeatureLifecycleTooltip
stage={currentStage!}
project={feature.project}
onArchive={onArchive}
onComplete={onComplete}
onUncomplete={onUncompleteHandler}
loading={loading}
>
<FeatureLifecycleStageIcon stage={currentStage!} />
</FeatureLifecycleTooltip>
<FeatureLifecycleStageIcon stage={currentStage} />
</LegacyFeatureLifecycleTooltip>
) : null;
};
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ test('render initial stage', async () => {

renderOpenTooltip({ name: 'initial', enteredStageAt });

await screen.findByText('initial');
await screen.findByText('Define');
await screen.findByText('2 minutes');
await screen.findByText(
'This feature flag is currently in the initial phase of its lifecycle.',
Expand All @@ -69,7 +69,7 @@ test('render pre-live stage', async () => {
enteredStageAt,
});

await screen.findByText('pre-live');
await screen.findByText('Develop');
await screen.findByText('development');
await screen.findByText('1 hour ago');
});
Expand All @@ -86,8 +86,8 @@ test('render live stage', async () => {
});

await screen.findByText('Is this feature complete?');
await screen.findByText('live');
await screen.findByText('production');
await screen.findByText('Production');
// await screen.findByText('production');
await screen.findByText('2 hours ago');
});

Expand All @@ -103,7 +103,7 @@ test('render completed stage with still active', async () => {
enteredStageAt,
});

await screen.findByText('completed');
await screen.findByText('Cleanup');
await screen.findByText('production');
await screen.findByText('2 hours ago');
expect(screen.queryByText('Archive feature')).not.toBeInTheDocument();
Expand All @@ -127,7 +127,7 @@ test('render completed stage safe to archive', async () => {
onArchive,
);

await screen.findByText('completed');
await screen.findByText('Cleanup');
const button = await screen.findByText('Archive feature');
button.click();

Expand All @@ -153,7 +153,7 @@ test('mark completed button gets activated', async () => {
onComplete,
);

await screen.findByText('live');
await screen.findByText('Production');
const button = await screen.findByText('Mark completed');
button.click();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Box, styled, Typography } from '@mui/material';
import { Badge } from 'component/common/Badge/Badge';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
import type * as React from 'react';
import type { FC } from 'react';
import CloudCircle from '@mui/icons-material/CloudCircle';
import { ReactComponent as UsageRate } from 'assets/icons/usage-rate.svg';
import { FeatureLifecycleStageIcon } from './FeatureLifecycleStageIcon';
import { FeatureLifecycleStageIcon } from 'component/common/FeatureLifecycle/FeatureLifecycleStageIcon';
import { TimeAgo } from 'component/common/TimeAgo/TimeAgo';
import { StyledIconWrapper } from '../../FeatureEnvironmentSeen/FeatureEnvironmentSeen';
import { useLastSeenColors } from '../../FeatureEnvironmentSeen/useLastSeenColors';
Expand All @@ -20,6 +19,7 @@ import { isSafeToArchive } from './isSafeToArchive';
import { useLocationSettings } from 'hooks/useLocationSettings';
import { formatDateYMDHMS } from 'utils/formatDate';
import { formatDistanceToNow, parseISO } from 'date-fns';
import { getFeatureLifecycleName } from 'component/common/FeatureLifecycle/getFeatureLifecycleName';

const TimeLabel = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
Expand Down Expand Up @@ -472,9 +472,9 @@ export const FeatureLifecycleTooltip: FC<{
gap: 1,
}}
>
<Badge sx={{ textTransform: 'capitalize' }}>
{stage.name}
</Badge>
<Typography variant='body2'>
{getFeatureLifecycleName(stage.name)}
</Typography>
<FeatureLifecycleStageIcon stage={stage} />
</Box>
</MainLifecycleRow>
Expand All @@ -487,7 +487,6 @@ export const FeatureLifecycleTooltip: FC<{
<TimeLabel>Time spent in stage</TimeLabel>
<FormatElapsedTime time={stage.enteredStageAt} />
</TimeLifecycleRow>
<StageTimeline stage={stage} />
</Box>
<ColorFill>
{stage.name === 'initial' && <InitialStageDescription />}
Expand Down
Loading

0 comments on commit 50ab2c9

Please sign in to comment.