diff --git a/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx b/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx index e10dc8a99d..9d13a9ec86 100644 --- a/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx @@ -33,7 +33,7 @@ const StyledBox = styled(Box)(({ theme }) => ({ margin: '0 auto', })); -const StyledIconWrapper = styled('div')(({ theme }) => ({ +export const StyledIconWrapper = styled('div')(({ theme }) => ({ width: '20px', height: '20px', background: theme.palette.background.paper, diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx index 2ba17ffe13..34d26247f8 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleStageIcon.tsx @@ -8,8 +8,14 @@ import { ReactComponent as ArchivedStageIcon } from 'assets/icons/stage-archived export type LifecycleStage = | { name: 'initial' } - | { name: 'pre-live' } - | { name: 'live' } + | { + name: 'pre-live'; + environments: Array<{ name: string; lastSeenAt: string }>; + } + | { + name: 'live'; + environments: Array<{ name: string; lastSeenAt: string }>; + } | { name: 'completed'; status: 'kept' | 'discarded'; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx index e37f02e0cb..72717fd8ff 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx @@ -9,10 +9,16 @@ 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'; +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 TimeAgo from 'react-timeago'; +import { StyledIconWrapper } from '../../FeatureEnvironmentSeen/FeatureEnvironmentSeen'; +import { useLastSeenColors } from '../../FeatureEnvironmentSeen/useLastSeenColors'; const TimeLabel = styled('span')(({ theme }) => ({ color: theme.palette.text.secondary, @@ -95,6 +101,159 @@ const ColorFill = styled(Box)(({ theme }) => ({ padding: theme.spacing(2, 3), })); +const LastSeenIcon: FC<{ lastSeen: string }> = ({ lastSeen }) => { + const getColor = useLastSeenColors(); + + return ( + { + const [color, textColor] = getColor(unit); + return ( + + + + ); + }} + /> + ); +}; + +const InitialStageDescription: FC = () => { + return ( + <> + + This feature toggle is currently in the initial phase of it's + life cycle. + + + This means that the flag has been created, but it has not yet + been seen in any environment. + + + Once we detect metrics for a non-production environment it will + move into pre-live. + + + ); +}; + +const StageTimeline: FC<{ stage: LifecycleStage }> = ({ stage }) => { + return ( + + + + + + + + + + + + + + + + + + + + + {stage.name === 'completed' && stage.status === 'discarded' ? ( + + ) : ( + + )} + + + + + + + + + ); +}; + +const EnvironmentLine = styled(Box)(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + marginTop: theme.spacing(1), + marginBottom: theme.spacing(2), +})); + +const CenteredBox = styled(Box)(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + gap: theme.spacing(1), +})); + +const LiveStageDescription: FC<{ + name: 'live' | 'pre-live'; + environments: Array<{ name: string; lastSeenAt: string }>; +}> = ({ name, environments }) => { + return ( + <> + + We've seen the feature flag in the following + non-production environments: + + } + /> + + Users have been exposed to this feature in the following + production environments: + + } + /> + + + {environments.map((environment) => { + return ( + + + + {environment.name} + + + + + + + ); + })} + + + ); +}; + export const FeatureLifecycleTooltip: FC<{ children: React.ReactElement; stage: LifecycleStage; @@ -129,69 +288,16 @@ export const FeatureLifecycleTooltip: FC<{ Time spent in stage 3 days - - - - - - - - - - - - - - - - - - - - - {stage.name === 'completed' && - stage.status === 'discarded' ? ( - - ) : ( - - )} - - - - - - - - + - - This feature toggle is currently in the initial phase of - it's life cycle. - - - This means that the flag has been created, but it has - not yet been seen in any environment. - - - Once we detect metrics for a non-production environment - it will move into pre-live. - + {stage.name === 'initial' && } + {(stage.name === 'pre-live' || stage.name === 'live') && ( + + )} }