Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lifecycle stage dates #6926

Merged
merged 1 commit into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import {
} from 'component/providers/AccessProvider/permissions';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { isSafeToArchive } from './isSafeToArchive';
import { useLocationSettings } from 'hooks/useLocationSettings';
import { formatDateYMDHMS } from 'utils/formatDate';
import { formatDistanceToNow, parseISO } from 'date-fns';

const TimeLabel = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
Expand Down Expand Up @@ -330,6 +333,18 @@ const CompletedStageDescription: FC<{
);
};

const FormatTime: FC<{ time: string }> = ({ time }) => {
const { locationSettings } = useLocationSettings();

return <span>{formatDateYMDHMS(time, locationSettings.locale)}</span>;
};

const FormatElapsedTime: FC<{ time: string }> = ({ time }) => {
const pastTime = parseISO(time);
const elapsedTime = formatDistanceToNow(pastTime, { addSuffix: false });
return <span>{elapsedTime}</span>;
};

export const FeatureLifecycleTooltip: FC<{
children: React.ReactElement<any, any>;
stage: LifecycleStage;
Expand Down Expand Up @@ -358,11 +373,12 @@ export const FeatureLifecycleTooltip: FC<{
</MainLifecycleRow>
<TimeLifecycleRow>
<TimeLabel>Stage entered at</TimeLabel>
<span>14/01/2024</span>

<FormatTime time={stage.enteredStageAt} />
</TimeLifecycleRow>
<TimeLifecycleRow>
<TimeLabel>Time spent in stage</TimeLabel>
<span>3 days</span>
<FormatElapsedTime time={stage.enteredStageAt} />
</TimeLifecycleRow>
<StageTimeline stage={stage} />
</Box>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
export type LifecycleStage =
| { name: 'initial' }
| {
name: 'pre-live';
environments: Array<{ name: string; lastSeenAt: string }>;
}
| {
name: 'live';
environments: Array<{ name: string; lastSeenAt: string }>;
}
| {
name: 'completed';
environments: Array<{ name: string; lastSeenAt: string }>;
status: 'kept' | 'discarded';
}
| { name: 'archived' };
type TimedStage = { enteredStageAt: string };
export type LifecycleStage = TimedStage &
(
| { name: 'initial' }
| {
name: 'pre-live';
environments: Array<{ name: string; lastSeenAt: string }>;
}
| {
name: 'live';
environments: Array<{ name: string; lastSeenAt: string }>;
}
| {
name: 'completed';
environments: Array<{ name: string; lastSeenAt: string }>;
status: 'kept' | 'discarded';
}
| { name: 'archived' }
);
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { populateCurrentStage } from './populateCurrentStage';
import type { IFeatureToggle } from '../../../../../interfaces/featureToggle';

const enteredStageAt = 'date';

describe('populateCurrentStage', () => {
it('should return undefined if lifecycle is not defined', () => {
const feature = {};
Expand All @@ -10,16 +12,16 @@ describe('populateCurrentStage', () => {

it('should return initial stage when lifecycle stage is initial', () => {
const feature = {
lifecycle: { stage: 'initial' },
lifecycle: { stage: 'initial', enteredStageAt },
};
const expected = { name: 'initial' };
const expected = { name: 'initial', enteredStageAt };
const result = populateCurrentStage(feature as IFeatureToggle);
expect(result).toEqual(expected);
});

it('should correctly populate pre-live stage with dev environments', () => {
const feature = {
lifecycle: { stage: 'pre-live' },
lifecycle: { stage: 'pre-live', enteredStageAt },
environments: [
{ name: 'test', type: 'development', lastSeenAt: null },
{ name: 'test1', type: 'production', lastSeenAt: '2022-08-01' },
Expand All @@ -29,29 +31,31 @@ describe('populateCurrentStage', () => {
const expected = {
name: 'pre-live',
environments: [{ name: 'dev', lastSeenAt: '2022-08-01' }],
enteredStageAt,
};
const result = populateCurrentStage(feature);
expect(result).toEqual(expected);
});

it('should handle live stage with production environments', () => {
const feature = {
lifecycle: { stage: 'live' },
lifecycle: { stage: 'live', enteredStageAt },
environments: [
{ name: 'prod', type: 'production', lastSeenAt: '2022-08-01' },
],
} as IFeatureToggle;
const expected = {
name: 'live',
environments: [{ name: 'prod', lastSeenAt: '2022-08-01' }],
enteredStageAt,
};
const result = populateCurrentStage(feature);
expect(result).toEqual(expected);
});

it('should return completed stage with production environments', () => {
const feature = {
lifecycle: { stage: 'completed' },
lifecycle: { stage: 'completed', enteredStageAt },
environments: [
{ name: 'prod', type: 'production', lastSeenAt: '2022-08-01' },
],
Expand All @@ -60,16 +64,17 @@ describe('populateCurrentStage', () => {
name: 'completed',
status: 'kept',
environments: [{ name: 'prod', lastSeenAt: '2022-08-01' }],
enteredStageAt,
};
const result = populateCurrentStage(feature);
expect(result).toEqual(expected);
});

it('should return archived stage when lifecycle stage is archived', () => {
const feature = {
lifecycle: { stage: 'archived' },
lifecycle: { stage: 'archived', enteredStageAt },
} as IFeatureToggle;
const expected = { name: 'archived' };
const expected = { name: 'archived', enteredStageAt };
const result = populateCurrentStage(feature);
expect(result).toEqual(expected);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,26 @@ export const populateCurrentStage = (
}));
};

const enteredStageAt = feature.lifecycle.enteredStageAt;

switch (feature.lifecycle.stage) {
case 'initial':
return { name: 'initial' };
return { name: 'initial', enteredStageAt };
case 'pre-live':
return {
name: 'pre-live',
environments: getFilteredEnvironments(
(type) => type !== 'production',
),
enteredStageAt,
};
case 'live':
return {
name: 'live',
environments: getFilteredEnvironments(
(type) => type === 'production',
),
enteredStageAt,
};
case 'completed':
return {
Expand All @@ -39,9 +43,10 @@ export const populateCurrentStage = (
environments: getFilteredEnvironments(
(type) => type === 'production',
),
enteredStageAt,
};
case 'archived':
return { name: 'archived' };
return { name: 'archived', enteredStageAt };
default:
return undefined;
}
Expand Down
Loading