mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
feat: Completed stage UI (#6917)
This commit is contained in:
parent
e91d471d17
commit
9c883ca37d
@ -17,7 +17,12 @@ import { StyledIconWrapper } from '../../FeatureEnvironmentSeen/FeatureEnvironme
|
||||
import { useLastSeenColors } from '../../FeatureEnvironmentSeen/useLastSeenColors';
|
||||
import type { LifecycleStage } from './LifecycleStage';
|
||||
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||
import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions';
|
||||
import {
|
||||
DELETE_FEATURE,
|
||||
UPDATE_FEATURE,
|
||||
} from 'component/providers/AccessProvider/permissions';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { isSafeToArchive } from './isSafeToArchive';
|
||||
|
||||
const TimeLabel = styled('span')(({ theme }) => ({
|
||||
color: theme.palette.text.secondary,
|
||||
@ -279,6 +284,52 @@ const LiveStageDescription: FC = ({ children }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const SafeToArchive: FC = () => {
|
||||
return (
|
||||
<>
|
||||
<BoldTitle>Safe to archive</BoldTitle>
|
||||
<InfoText sx={{ mt: 2, mb: 1 }}>
|
||||
We haven’t seen this feature flag in production for at least two
|
||||
days. It’s likely that it’s safe to archive this flag.
|
||||
</InfoText>
|
||||
<PermissionButton
|
||||
color='inherit'
|
||||
variant='outlined'
|
||||
permission={DELETE_FEATURE}
|
||||
size='small'
|
||||
sx={{ mb: 2 }}
|
||||
>
|
||||
Archive feature
|
||||
</PermissionButton>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ActivelyUsed: FC = ({ children }) => {
|
||||
return (
|
||||
<>
|
||||
<InfoText sx={{ mt: 1, mb: 1 }}>
|
||||
This feature has been successfully completed, but we are still
|
||||
seeing usage in production. Clean up the feature flag from your
|
||||
code before archiving it:
|
||||
</InfoText>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const CompletedStageDescription: FC<{
|
||||
environments: Array<{ name: string; lastSeenAt: string }>;
|
||||
}> = ({ children, environments }) => {
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={isSafeToArchive(environments)}
|
||||
show={<SafeToArchive />}
|
||||
elseShow={<ActivelyUsed>{children}</ActivelyUsed>}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const FeatureLifecycleTooltip: FC<{
|
||||
children: React.ReactElement<any, any>;
|
||||
stage: LifecycleStage;
|
||||
@ -327,6 +378,13 @@ export const FeatureLifecycleTooltip: FC<{
|
||||
<Environments environments={stage.environments} />
|
||||
</LiveStageDescription>
|
||||
)}
|
||||
{stage.name === 'completed' && (
|
||||
<CompletedStageDescription
|
||||
environments={stage.environments}
|
||||
>
|
||||
<Environments environments={stage.environments} />
|
||||
</CompletedStageDescription>
|
||||
)}
|
||||
</ColorFill>
|
||||
</Box>
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ export type LifecycleStage =
|
||||
}
|
||||
| {
|
||||
name: 'completed';
|
||||
environments: Array<{ name: string; lastSeenAt: string }>;
|
||||
status: 'kept' | 'discarded';
|
||||
}
|
||||
| { name: 'archived' };
|
||||
|
@ -0,0 +1,44 @@
|
||||
import { isSafeToArchive } from './isSafeToArchive'; // Update the import path accordingly
|
||||
import { subDays } from 'date-fns';
|
||||
|
||||
describe('isSafeToArchive', () => {
|
||||
it('should return true if all environments were last seen more than two days ago', () => {
|
||||
const now = new Date();
|
||||
const environments = [
|
||||
{ name: 'Production', lastSeenAt: subDays(now, 3).toISOString() },
|
||||
{ name: 'Staging', lastSeenAt: subDays(now, 4).toISOString() },
|
||||
];
|
||||
|
||||
const result = isSafeToArchive(environments);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if any environment was seen within the last two days', () => {
|
||||
const now = new Date();
|
||||
const environments = [
|
||||
{ name: 'Production', lastSeenAt: subDays(now, 3).toISOString() },
|
||||
{ name: 'Staging', lastSeenAt: subDays(now, 1).toISOString() },
|
||||
];
|
||||
|
||||
const result = isSafeToArchive(environments);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if all environments were seen within the last two days', () => {
|
||||
const now = new Date();
|
||||
const environments = [
|
||||
{ name: 'Production', lastSeenAt: subDays(now, 0).toISOString() },
|
||||
{ name: 'Staging', lastSeenAt: subDays(now, 1).toISOString() },
|
||||
];
|
||||
|
||||
const result = isSafeToArchive(environments);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for an empty array of environments', () => {
|
||||
const environments: Array<{ name: string; lastSeenAt: string }> = [];
|
||||
|
||||
const result = isSafeToArchive(environments);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
@ -0,0 +1,13 @@
|
||||
import { isBefore, parseISO, subDays } from 'date-fns';
|
||||
|
||||
export function isSafeToArchive(
|
||||
environments: Array<{ name: string; lastSeenAt: string }>,
|
||||
) {
|
||||
const twoDaysAgo = subDays(new Date(), 2);
|
||||
|
||||
return environments.every((env) => {
|
||||
const lastSeenDate = parseISO(env.lastSeenAt);
|
||||
|
||||
return isBefore(lastSeenDate, twoDaysAgo);
|
||||
});
|
||||
}
|
@ -83,7 +83,8 @@ const FeatureOverviewMetaData = () => {
|
||||
const IconComponent = getFeatureTypeIcons(type);
|
||||
|
||||
const currentStage: LifecycleStage = {
|
||||
name: 'live',
|
||||
name: 'completed',
|
||||
status: 'kept',
|
||||
environments: [
|
||||
{ name: 'production', lastSeenAt: new Date().toISOString() },
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user