mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: flag lifecycle status - first pass (#9736)
Resolving "status" column for flags overview page
This commit is contained in:
		
							parent
							
								
									67c0ffa1ab
								
							
						
					
					
						commit
						1043eb8f03
					
				| @ -41,6 +41,7 @@ import { LifecycleFilters } from './FeatureToggleFilters/LifecycleFilters'; | ||||
| import { ExportFlags } from './ExportFlags'; | ||||
| import { createFeatureOverviewCell } from 'component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell'; | ||||
| import { AvatarCell } from 'component/project/Project/PaginatedProjectFeatureToggles/AvatarCell'; | ||||
| import { StatusCell } from './StatusCell/StatusCell'; | ||||
| 
 | ||||
| export const featuresPlaceholder = Array(15).fill({ | ||||
|     name: 'Name of the feature', | ||||
| @ -175,7 +176,6 @@ export const FeatureToggleListTable: FC = () => { | ||||
|                           meta: { width: '1%', align: 'center' }, | ||||
|                           enableSorting: false, | ||||
|                       }), | ||||
| 
 | ||||
|                       columnHelper.accessor('lifecycle', { | ||||
|                           id: 'lifecycle', | ||||
|                           header: 'Lifecycle', | ||||
| @ -190,6 +190,15 @@ export const FeatureToggleListTable: FC = () => { | ||||
|                           size: 50, | ||||
|                           meta: { width: '1%' }, | ||||
|                       }), | ||||
|                       columnHelper.accessor('environments', { | ||||
|                           id: 'status', | ||||
|                           header: 'Status', | ||||
|                           cell: ({ row: { original } }) => ( | ||||
|                               <StatusCell {...original} /> | ||||
|                           ), | ||||
|                           enableSorting: false, | ||||
|                           size: 50, | ||||
|                       }), | ||||
|                       columnHelper.accessor('project', { | ||||
|                           header: 'Project', | ||||
|                           cell: ({ getValue }) => { | ||||
|  | ||||
| @ -0,0 +1,20 @@ | ||||
| import { type FC, useMemo } from 'react'; | ||||
| import type { FeatureSearchResponseSchema } from 'openapi'; | ||||
| import { styled } from '@mui/material'; | ||||
| import { getStatus } from './getStatus'; | ||||
| 
 | ||||
| const Container = styled('div')(({ theme }) => ({ | ||||
|     padding: theme.spacing(0, 2), | ||||
| })); | ||||
| 
 | ||||
| export const StatusCell: FC<FeatureSearchResponseSchema> = ({ | ||||
|     lifecycle, | ||||
|     environments, | ||||
| }) => { | ||||
|     const status = useMemo( | ||||
|         () => getStatus({ lifecycle, environments }), | ||||
|         [lifecycle, environments], | ||||
|     ); | ||||
| 
 | ||||
|     return <Container>{status}</Container>; | ||||
| }; | ||||
| @ -0,0 +1,151 @@ | ||||
| import { getStatus } from './getStatus'; | ||||
| import { PRODUCTION } from 'constants/environmentTypes'; | ||||
| import type { FeatureSearchEnvironmentSchema } from 'openapi'; | ||||
| 
 | ||||
| const prodEnvEnabled: FeatureSearchEnvironmentSchema = { | ||||
|     name: 'production', | ||||
|     enabled: true, | ||||
|     type: PRODUCTION, | ||||
|     sortOrder: 1, | ||||
|     variantCount: 0, | ||||
|     lastSeenAt: null, | ||||
|     hasStrategies: true, | ||||
|     hasEnabledStrategies: true, | ||||
| }; | ||||
| 
 | ||||
| const prodEnvDisabled: FeatureSearchEnvironmentSchema = { | ||||
|     ...prodEnvEnabled, | ||||
|     enabled: false, | ||||
|     hasEnabledStrategies: false, | ||||
| }; | ||||
| 
 | ||||
| const prodEnvDisabledNoStrategies: FeatureSearchEnvironmentSchema = { | ||||
|     ...prodEnvDisabled, | ||||
|     hasStrategies: false, | ||||
| }; | ||||
| 
 | ||||
| const devEnvEnabled: FeatureSearchEnvironmentSchema = { | ||||
|     name: 'development', | ||||
|     enabled: true, | ||||
|     type: 'development', | ||||
|     sortOrder: 0, | ||||
|     variantCount: 0, | ||||
|     lastSeenAt: null, | ||||
|     hasStrategies: true, | ||||
|     hasEnabledStrategies: true, | ||||
| }; | ||||
| 
 | ||||
| const devEnvDisabledWithStrategies: FeatureSearchEnvironmentSchema = { | ||||
|     ...devEnvEnabled, | ||||
|     enabled: false, | ||||
|     hasEnabledStrategies: false, | ||||
| }; | ||||
| 
 | ||||
| const devEnvDisabledNoStrategies: FeatureSearchEnvironmentSchema = { | ||||
|     ...devEnvDisabledWithStrategies, | ||||
|     hasStrategies: false, | ||||
| }; | ||||
| 
 | ||||
| describe('getStatus', () => { | ||||
|     describe("lifecycle 'define' stage", () => { | ||||
|         it('has no strategies', () => { | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [devEnvDisabledNoStrategies, prodEnvDisabled], | ||||
|                     lifecycle: { | ||||
|                         stage: 'initial', | ||||
|                         enteredStageAt: null as any, | ||||
|                     }, | ||||
|                 }), | ||||
|             ).toBe('No strategies'); | ||||
|         }); | ||||
| 
 | ||||
|         it('has no enabled strategies', () => { | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [ | ||||
|                         devEnvDisabledWithStrategies, | ||||
|                         prodEnvDisabled, | ||||
|                     ], | ||||
|                     lifecycle: { | ||||
|                         stage: 'initial', | ||||
|                         enteredStageAt: null as any, | ||||
|                     }, | ||||
|                 }), | ||||
|             ).toBe('No enabled strategies'); | ||||
|         }); | ||||
| 
 | ||||
|         it('has a non-production environment enabled', () => { | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [devEnvEnabled], | ||||
|                     lifecycle: { | ||||
|                         stage: 'initial', | ||||
|                         enteredStageAt: null as any, | ||||
|                     }, | ||||
|                 }), | ||||
|             ).toBe('No traffic'); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     describe("lifecycle 'develop' stage", () => { | ||||
|         it('is paused', () => { | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [ | ||||
|                         devEnvDisabledWithStrategies, | ||||
|                         prodEnvDisabled, | ||||
|                     ], | ||||
|                     lifecycle: { | ||||
|                         stage: 'pre-live', | ||||
|                         enteredStageAt: null as any, | ||||
|                     }, | ||||
|                 }), | ||||
|             ).toBe('Paused'); | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [devEnvEnabled, prodEnvDisabled], | ||||
|                     lifecycle: { | ||||
|                         stage: 'pre-live', | ||||
|                         enteredStageAt: null as any, | ||||
|                     }, | ||||
|                 }), | ||||
|             ).not.toBe('Paused'); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     describe("lifecycle 'production' stage", () => { | ||||
|         it('has no production environments', () => { | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [devEnvEnabled], | ||||
|                     lifecycle: { stage: 'live', enteredStageAt: null as any }, | ||||
|                 }), | ||||
|             ).toBe('No production environments'); | ||||
|         }); | ||||
| 
 | ||||
|         it('is paused', () => { | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [prodEnvDisabled], | ||||
|                     lifecycle: { stage: 'live', enteredStageAt: null as any }, | ||||
|                 }), | ||||
|             ).toBe('Paused'); | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [prodEnvEnabled], | ||||
|                     lifecycle: { stage: 'live', enteredStageAt: null as any }, | ||||
|                 }), | ||||
|             ).not.toBe('Paused'); | ||||
|         }); | ||||
| 
 | ||||
|         it('has no produciton strategies', () => { | ||||
|             expect( | ||||
|                 getStatus({ | ||||
|                     environments: [prodEnvDisabledNoStrategies], | ||||
|                     lifecycle: { stage: 'live', enteredStageAt: null as any }, | ||||
|                 }), | ||||
|             ).toBe('No strategies'); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @ -0,0 +1,66 @@ | ||||
| import { PRODUCTION } from 'constants/environmentTypes'; | ||||
| import type { FeatureSearchResponseSchema } from 'openapi'; | ||||
| 
 | ||||
| export const getStatus = ({ | ||||
|     lifecycle, | ||||
|     environments, | ||||
| }: Pick< | ||||
|     FeatureSearchResponseSchema, | ||||
|     'lifecycle' | 'environments' | 'lastSeenAt' | ||||
| >) => { | ||||
|     if (lifecycle?.stage === 'initial') { | ||||
|         if ( | ||||
|             environments?.some((env) => env.type !== PRODUCTION && env.enabled) | ||||
|         ) { | ||||
|             return 'No traffic'; | ||||
|         } | ||||
| 
 | ||||
|         if ( | ||||
|             !environments?.some( | ||||
|                 (env) => env.type !== PRODUCTION && env.hasStrategies, | ||||
|             ) | ||||
|         ) { | ||||
|             return 'No strategies'; | ||||
|         } | ||||
| 
 | ||||
|         if ( | ||||
|             !environments?.some( | ||||
|                 (env) => env.type !== PRODUCTION && env.hasEnabledStrategies, | ||||
|             ) | ||||
|         ) { | ||||
|             return 'No enabled strategies'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (lifecycle?.stage === 'pre-live') { | ||||
|         if (!environments?.some((env) => env.enabled)) { | ||||
|             return 'Paused'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     const productionEnvironment = environments?.find( | ||||
|         (env) => env.type === PRODUCTION, | ||||
|     ); | ||||
| 
 | ||||
|     if (lifecycle?.stage === 'live') { | ||||
|         if (!productionEnvironment) { | ||||
|             return 'No production environments'; | ||||
|         } | ||||
| 
 | ||||
|         if (!productionEnvironment?.hasStrategies) { | ||||
|             return 'No strategies'; | ||||
|         } | ||||
| 
 | ||||
|         if (!productionEnvironment?.enabled) { | ||||
|             return 'Paused'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (lifecycle?.stage === 'completed') { | ||||
|         if (productionEnvironment?.enabled) { | ||||
|             return 'Enabled'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return '–'; | ||||
| }; | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user