Skip to content

Commit

Permalink
feat: completed stage button (#6914)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew committed Apr 24, 2024
1 parent f63bae2 commit e91d471
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 it’s 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}
</>
);
};
Expand Down Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
@@ -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' };
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand Down

0 comments on commit e91d471

Please sign in to comment.