1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-04 00:18:01 +01:00

feat: completed stage button (#6914)

This commit is contained in:
Mateusz Kwasniewski 2024-04-24 10:30:50 +02:00 committed by GitHub
parent f63bae21f5
commit e91d471d17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 111 additions and 72 deletions

View File

@ -5,22 +5,7 @@ import { ReactComponent as LiveStageIcon } from 'assets/icons/stage-live.svg';
import { ReactComponent as CompletedStageIcon } from 'assets/icons/stage-completed.svg';
import { ReactComponent as CompletedDiscardedStageIcon } from 'assets/icons/stage-completed-discarded.svg';
import { ReactComponent as ArchivedStageIcon } from 'assets/icons/stage-archived.svg';
export type LifecycleStage =
| { name: 'initial' }
| {
name: 'pre-live';
environments: Array<{ name: string; lastSeenAt: string }>;
}
| {
name: 'live';
environments: Array<{ name: string; lastSeenAt: string }>;
}
| {
name: 'completed';
status: 'kept' | 'discarded';
}
| { name: 'archived' };
import type { LifecycleStage } from './LifecycleStage';
export const FeatureLifecycleStageIcon: FC<{ stage: LifecycleStage }> = ({
stage,

View File

@ -11,14 +11,13 @@ import { ReactComponent as CompletedDiscardedStageIcon } from 'assets/icons/stag
import { ReactComponent as ArchivedStageIcon } from 'assets/icons/stage-archived.svg';
import CloudCircle from '@mui/icons-material/CloudCircle';
import { ReactComponent as UsageRate } from 'assets/icons/usage-rate.svg';
import {
FeatureLifecycleStageIcon,
type LifecycleStage,
} from './FeatureLifecycleStageIcon';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { FeatureLifecycleStageIcon } from './FeatureLifecycleStageIcon';
import TimeAgo from 'react-timeago';
import { StyledIconWrapper } from '../../FeatureEnvironmentSeen/FeatureEnvironmentSeen';
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';
const TimeLabel = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
@ -204,52 +203,78 @@ const CenteredBox = styled(Box)(({ theme }) => ({
gap: theme.spacing(1),
}));
const LiveStageDescription: FC<{
name: 'live' | 'pre-live';
const Environments: FC<{
environments: Array<{ name: string; lastSeenAt: string }>;
}> = ({ name, environments }) => {
}> = ({ environments }) => {
return (
<Box>
{environments.map((environment) => {
return (
<EnvironmentLine key={environment.name}>
<CenteredBox>
<CloudCircle />
<Box>{environment.name}</Box>
</CenteredBox>
<CenteredBox>
<TimeAgo
minPeriod={60}
date={environment.lastSeenAt}
/>
<LastSeenIcon lastSeen={environment.lastSeenAt} />
</CenteredBox>
</EnvironmentLine>
);
})}
</Box>
);
};
const PreLiveStageDescription: FC = ({ children }) => {
return (
<>
<ConditionallyRender
condition={name === 'pre-live'}
show={
<InfoText>
We've seen the feature flag in the following
non-production environments:
</InfoText>
}
/>
<ConditionallyRender
condition={name === 'live'}
show={
<InfoText>
Users have been exposed to this feature in the following
production environments:
</InfoText>
}
/>
<InfoText>
We've seen the feature flag in the following non-production
environments:
</InfoText>
<Box>
{environments.map((environment) => {
return (
<EnvironmentLine key={environment.name}>
<CenteredBox>
<CloudCircle />
<Box>{environment.name}</Box>
</CenteredBox>
<CenteredBox>
<TimeAgo
minPeriod={60}
date={environment.lastSeenAt}
/>
<LastSeenIcon
lastSeen={environment.lastSeenAt}
/>
</CenteredBox>
</EnvironmentLine>
);
})}
</Box>
{children}
</>
);
};
const BoldTitle = styled(Typography)(({ theme }) => ({
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
fontSize: theme.fontSizes.smallBody,
fontWeight: theme.fontWeight.bold,
}));
const LiveStageDescription: FC = ({ children }) => {
return (
<>
<BoldTitle>Is this feature complete?</BoldTitle>
<InfoText sx={{ mb: 1 }}>
Marking the feature as complete does not affect any
configuration, but it moves the feature into its next life
cycle stage and is an indication that you have learned what you
needed in order to progress with the feature. It serves as a
reminder to start cleaning up the flag and removing it from the
code.
</InfoText>
<PermissionButton
color='inherit'
variant='outlined'
permission={UPDATE_FEATURE}
size='small'
>
Mark Completed
</PermissionButton>
<InfoText sx={{ mt: 3 }}>
Users have been exposed to this feature in the following
production environments:
</InfoText>
{children}
</>
);
};
@ -292,11 +317,15 @@ export const FeatureLifecycleTooltip: FC<{
</Box>
<ColorFill>
{stage.name === 'initial' && <InitialStageDescription />}
{(stage.name === 'pre-live' || stage.name === 'live') && (
<LiveStageDescription
name={stage.name}
environments={stage.environments}
/>
{stage.name === 'pre-live' && (
<PreLiveStageDescription>
<Environments environments={stage.environments} />
</PreLiveStageDescription>
)}
{stage.name === 'live' && (
<LiveStageDescription>
<Environments environments={stage.environments} />
</LiveStageDescription>
)}
</ColorFill>
</Box>

View File

@ -0,0 +1,15 @@
export type LifecycleStage =
| { name: 'initial' }
| {
name: 'pre-live';
environments: Array<{ name: string; lastSeenAt: string }>;
}
| {
name: 'live';
environments: Array<{ name: string; lastSeenAt: string }>;
}
| {
name: 'completed';
status: 'kept' | 'discarded';
}
| { name: 'archived' };

View File

@ -10,6 +10,7 @@ import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useUiFlag } from 'hooks/useUiFlag';
import { FeatureLifecycleTooltip } from '../FeatureLifecycle/FeatureLifecycleTooltip';
import { FeatureLifecycleStageIcon } from '../FeatureLifecycle/FeatureLifecycleStageIcon';
import type { LifecycleStage } from '../FeatureLifecycle/LifecycleStage';
const StyledContainer = styled('div')(({ theme }) => ({
borderRadius: theme.shape.borderRadiusLarge,
@ -81,6 +82,17 @@ const FeatureOverviewMetaData = () => {
const IconComponent = getFeatureTypeIcons(type);
const currentStage: LifecycleStage = {
name: 'live',
environments: [
{ name: 'production', lastSeenAt: new Date().toISOString() },
{
name: 'staging',
lastSeenAt: new Date().toISOString(),
},
],
};
return (
<StyledContainer>
<StyledPaddingContainerTop>
@ -109,11 +121,9 @@ const FeatureOverviewMetaData = () => {
show={
<StyledRow data-loading>
<StyledLabel>Lifecycle:</StyledLabel>
<FeatureLifecycleTooltip
stage={{ name: 'initial' }}
>
<FeatureLifecycleTooltip stage={currentStage}>
<FeatureLifecycleStageIcon
stage={{ name: 'initial' }}
stage={currentStage}
/>
</FeatureLifecycleTooltip>
</StyledRow>