From 27e6869e5621c56981507c99ee66013af4677282 Mon Sep 17 00:00:00 2001 From: David An Date: Wed, 26 Apr 2023 11:47:54 -0700 Subject: [PATCH] sort feature flag Signed-off-by: David An --- .../LocalStorageFeatureFlags.test.tsx | 47 +++++++++++++++++++ .../LocalStorageFeatureFlags.tsx | 7 +++ .../src/apis/definitions/FeatureFlagsApi.ts | 5 ++ .../ExploreLayout/ExploreLayout.test.tsx | 1 + .../TemplatePage/TemplatePage.test.tsx | 1 + .../FeatureFlags/UserSettingsFeatureFlags.tsx | 21 ++++++++- 6 files changed, 81 insertions(+), 1 deletion(-) diff --git a/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.test.tsx b/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.test.tsx index 1193592e96..a0b04a922c 100644 --- a/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.test.tsx +++ b/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.test.tsx @@ -218,4 +218,51 @@ describe('FeatureFlags', () => { ).toThrow(/only contain lowercase letters, numbers and hyphens/i); }); }); + + describe('getSortedRegisteredFlags', () => { + let featureFlags: FeatureFlagsApi; + + beforeEach(() => { + featureFlags = new LocalStorageFeatureFlags(); + }); + + it('should return empty list', () => { + expect(featureFlags.getSortedFlags()).toEqual([]); + }); + + it('loads active flags first in registered order', () => { + featureFlags.registerFlag({ + name: 'registered-flag-1', + pluginId: 'plugin-one', + }); + featureFlags.registerFlag({ + name: 'registered-flag-2', + pluginId: 'plugin-two', + }); + featureFlags.registerFlag({ + name: 'registered-flag-3', + pluginId: 'plugin-three', + }); + featureFlags.registerFlag({ + name: 'registered-flag-4', + pluginId: 'plugin-four', + }); + + featureFlags.save({ + states: { + 'registered-flag-1': FeatureFlagState.None, + 'registered-flag-2': FeatureFlagState.Active, + 'registered-flag-3': FeatureFlagState.None, + 'registered-flag-4': FeatureFlagState.Active, + }, + }); + + expect(featureFlags.getSortedFlags()).toEqual([ + { name: 'registered-flag-2', pluginId: 'plugin-two' }, + { name: 'registered-flag-4', pluginId: 'plugin-four' }, + { name: 'registered-flag-1', pluginId: 'plugin-one' }, + { name: 'registered-flag-3', pluginId: 'plugin-three' }, + ]); + }); + }); }); diff --git a/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.tsx b/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.tsx index 2c8470642a..08333b1161 100644 --- a/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.tsx +++ b/packages/core-app-api/src/apis/implementations/FeatureFlagsApi/LocalStorageFeatureFlags.tsx @@ -57,6 +57,13 @@ export class LocalStorageFeatureFlags implements FeatureFlagsApi { this.registeredFeatureFlags.push(flag); } + getSortedFlags(): FeatureFlag[] { + const flags = this.registeredFeatureFlags; + const activeFlags = flags.filter(flag => this.isActive(flag.name)); + const idleFlags = flags.filter(flag => !this.isActive(flag.name)); + return [...activeFlags, ...idleFlags]; + } + getRegisteredFlags(): FeatureFlag[] { return this.registeredFeatureFlags.slice(); } diff --git a/packages/core-plugin-api/src/apis/definitions/FeatureFlagsApi.ts b/packages/core-plugin-api/src/apis/definitions/FeatureFlagsApi.ts index 66260afa32..1dcc1ba74d 100644 --- a/packages/core-plugin-api/src/apis/definitions/FeatureFlagsApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/FeatureFlagsApi.ts @@ -84,6 +84,11 @@ export interface FeatureFlagsApi { */ registerFlag(flag: FeatureFlag): void; + /** + * Get a list of all registered flags sorted. + */ + getSortedFlags(): FeatureFlag[]; + /** * Get a list of all registered flags. */ diff --git a/plugins/explore/src/components/ExploreLayout/ExploreLayout.test.tsx b/plugins/explore/src/components/ExploreLayout/ExploreLayout.test.tsx index 7574c685a4..808a0d9dec 100644 --- a/plugins/explore/src/components/ExploreLayout/ExploreLayout.test.tsx +++ b/plugins/explore/src/components/ExploreLayout/ExploreLayout.test.tsx @@ -29,6 +29,7 @@ const featureFlagsApi: jest.Mocked = { save: jest.fn(), getRegisteredFlags: jest.fn(), registerFlag: jest.fn(), + getSortedFlags: jest.fn(), }; describe('', () => { diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx index 344929fa43..1854f4a307 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.test.tsx @@ -62,6 +62,7 @@ const featureFlagsApiMock: jest.Mocked = { registerFlag: jest.fn(), getRegisteredFlags: jest.fn(), save: jest.fn(), + getSortedFlags: jest.fn(), }; const errorApiMock = { post: jest.fn(), error$: jest.fn() }; diff --git a/plugins/user-settings/src/components/FeatureFlags/UserSettingsFeatureFlags.tsx b/plugins/user-settings/src/components/FeatureFlags/UserSettingsFeatureFlags.tsx index c58e637bd2..67356381ce 100644 --- a/plugins/user-settings/src/components/FeatureFlags/UserSettingsFeatureFlags.tsx +++ b/plugins/user-settings/src/components/FeatureFlags/UserSettingsFeatureFlags.tsx @@ -25,6 +25,7 @@ import { import { EmptyFlags } from './EmptyFlags'; import { FlagItem } from './FeatureFlagsItem'; import { + FeatureFlag, featureFlagsApiRef, FeatureFlagState, useApi, @@ -32,11 +33,27 @@ import { import { InfoCard } from '@backstage/core-components'; import ClearIcon from '@material-ui/icons/Clear'; +let registered = false; +const f1: FeatureFlag = { name: 'f111', pluginId: 'f111' }; +const f2: FeatureFlag = { name: 'f222', pluginId: 'f222' }; +const f3: FeatureFlag = { name: 'f333', pluginId: 'f333' }; +const f4: FeatureFlag = { name: 'f444', pluginId: 'f444' }; +const f5: FeatureFlag = { name: 'f555', pluginId: 'f555' }; /** @public */ export const UserSettingsFeatureFlags = () => { const featureFlagsApi = useApi(featureFlagsApiRef); - const featureFlags = featureFlagsApi.getRegisteredFlags(); + if (!registered) { + featureFlagsApi.registerFlag(f1); + featureFlagsApi.registerFlag(f2); + featureFlagsApi.registerFlag(f3); + featureFlagsApi.registerFlag(f4); + featureFlagsApi.registerFlag(f5); + registered = true; + } + + // featureFlagsApi.sortFlags(); + const featureFlags = featureFlagsApi.getSortedFlags(); const initialFlagState = Object.fromEntries( featureFlags.map(({ name }) => [name, featureFlagsApi.isActive(name)]), ); @@ -132,3 +149,5 @@ export const UserSettingsFeatureFlags = () => { ); }; + +export default React.memo(UserSettingsFeatureFlags);