-
-
Notifications
You must be signed in to change notification settings - Fork 256
feat: add override functionality to remote feature flags #7271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
bec04d7
e78270a
fe7db8b
4413b2d
e07e67c
ec17188
fbdbd14
c9cd5aa
4d02e47
e3a4f8f
35b8470
4201e40
7ae47a3
71e4b7a
ca479c8
0063bce
9bbf745
414f0f0
f17c947
4d349ed
6a6b98f
7e3500d
434c892
6c75509
e562809
a09ceaa
ffd58e9
c1af969
9d99264
1f49998
e8f2ff1
83017de
6447545
28a8548
c3d09e5
10c168d
d1357b7
fb818a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,3 +51,25 @@ export type ServiceResponse = { | |
| remoteFeatureFlags: FeatureFlags; | ||
| cacheTimestamp: number | null; | ||
| }; | ||
|
|
||
| /** | ||
| * Describes the shape of the state object for the {@link RemoteFeatureFlagController}. | ||
| */ | ||
| export type RemoteFeatureFlagControllerState = { | ||
| /** | ||
| * The collection of feature flags and their respective values, which can be objects. | ||
| */ | ||
| remoteFeatureFlags: FeatureFlags; | ||
| /** | ||
| * Local overrides for feature flags that take precedence over remote flags. | ||
| */ | ||
| localOverrides: FeatureFlags; | ||
| /** | ||
| * Raw A/B test flag arrays for flags that were processed from arrays to single values. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this always true? Will feature flags always contain A/B test arrays from now on? There don't seem to be any changes to the |
||
| */ | ||
| rawRemoteFeatureFlags: FeatureFlags; | ||
| /** | ||
| * The timestamp of the last successful feature flag cache. | ||
| */ | ||
| cacheTimestamp: number; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,6 +9,7 @@ import type { | |||||||||||||||||||||||||
| import type { AbstractClientConfigApiService } from './client-config-api-service/abstract-client-config-api-service'; | ||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||
| RemoteFeatureFlagController, | ||||||||||||||||||||||||||
| controllerName, | ||||||||||||||||||||||||||
| DEFAULT_CACHE_DURATION, | ||||||||||||||||||||||||||
| getDefaultRemoteFeatureFlagControllerState, | ||||||||||||||||||||||||||
| } from './remote-feature-flag-controller'; | ||||||||||||||||||||||||||
|
|
@@ -18,8 +19,6 @@ import type { | |||||||||||||||||||||||||
| } from './remote-feature-flag-controller'; | ||||||||||||||||||||||||||
| import type { FeatureFlags } from './remote-feature-flag-controller-types'; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const controllerName = 'RemoteFeatureFlagController'; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const MOCK_FLAGS: FeatureFlags = { | ||||||||||||||||||||||||||
| feature1: true, | ||||||||||||||||||||||||||
| feature2: { chrome: '<109' }, | ||||||||||||||||||||||||||
|
|
@@ -88,6 +87,8 @@ describe('RemoteFeatureFlagController', () => { | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state).toStrictEqual({ | ||||||||||||||||||||||||||
| remoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| localOverrides: {}, | ||||||||||||||||||||||||||
| rawRemoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| cacheTimestamp: 0, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
@@ -97,6 +98,8 @@ describe('RemoteFeatureFlagController', () => { | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state).toStrictEqual({ | ||||||||||||||||||||||||||
| remoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| localOverrides: {}, | ||||||||||||||||||||||||||
| rawRemoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| cacheTimestamp: 0, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
@@ -105,6 +108,8 @@ describe('RemoteFeatureFlagController', () => { | |||||||||||||||||||||||||
| const customState = { | ||||||||||||||||||||||||||
| remoteFeatureFlags: MOCK_FLAGS_TWO, | ||||||||||||||||||||||||||
| cacheTimestamp: 123456789, | ||||||||||||||||||||||||||
| rawRemoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| localOverrides: {}, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const controller = createController({ state: customState }); | ||||||||||||||||||||||||||
|
|
@@ -640,11 +645,116 @@ describe('RemoteFeatureFlagController', () => { | |||||||||||||||||||||||||
| it('should return default state', () => { | ||||||||||||||||||||||||||
| expect(getDefaultRemoteFeatureFlagControllerState()).toStrictEqual({ | ||||||||||||||||||||||||||
| remoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| localOverrides: {}, | ||||||||||||||||||||||||||
| rawRemoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| cacheTimestamp: 0, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| describe('override functionality', () => { | ||||||||||||||||||||||||||
| describe('setFlagOverride', () => { | ||||||||||||||||||||||||||
| it('sets a local override for a feature flag', () => { | ||||||||||||||||||||||||||
| const controller = createController(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| controller.setFlagOverride('testFlag', true); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state.localOverrides).toStrictEqual({ | ||||||||||||||||||||||||||
| testFlag: true, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| it('overwrites existing override for the same flag', () => { | ||||||||||||||||||||||||||
| const controller = createController(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| controller.setFlagOverride('testFlag', true); | ||||||||||||||||||||||||||
|
Comment on lines
+668
to
+670
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of calling the method to prepare the state, and then calling it again to test the intended behavior, what are your thoughts on passing initial state to
Suggested change
|
||||||||||||||||||||||||||
| controller.setFlagOverride('testFlag', false); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state.localOverrides).toStrictEqual({ | ||||||||||||||||||||||||||
| testFlag: false, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| it('preserves other overrides when setting a new one', () => { | ||||||||||||||||||||||||||
| const controller = createController(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| controller.setFlagOverride('flag1', 'value1'); | ||||||||||||||||||||||||||
|
Comment on lines
+679
to
+681
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar suggestion as above:
Suggested change
|
||||||||||||||||||||||||||
| controller.setFlagOverride('flag2', 'value2'); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state.localOverrides).toStrictEqual({ | ||||||||||||||||||||||||||
| flag1: 'value1', | ||||||||||||||||||||||||||
| flag2: 'value2', | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| describe('removeFlagOverride', () => { | ||||||||||||||||||||||||||
| it('removes a specific override', () => { | ||||||||||||||||||||||||||
| const controller = createController(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| controller.setFlagOverride('flag1', 'value1'); | ||||||||||||||||||||||||||
| controller.setFlagOverride('flag2', 'value2'); | ||||||||||||||||||||||||||
|
Comment on lines
+693
to
+696
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar suggestion as above. We are testing
Suggested change
|
||||||||||||||||||||||||||
| controller.removeFlagOverride('flag1'); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state.localOverrides).toStrictEqual({ | ||||||||||||||||||||||||||
| flag2: 'value2', | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| it('does not affect state when clearing non-existent override', () => { | ||||||||||||||||||||||||||
| const controller = createController(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| controller.setFlagOverride('flag1', 'value1'); | ||||||||||||||||||||||||||
|
Comment on lines
+705
to
+707
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar:
Suggested change
|
||||||||||||||||||||||||||
| controller.removeFlagOverride('nonExistentFlag'); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state.localOverrides).toStrictEqual({ | ||||||||||||||||||||||||||
| flag1: 'value1', | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| describe('clearAllFlagOverrides', () => { | ||||||||||||||||||||||||||
| it('removes all overrides', () => { | ||||||||||||||||||||||||||
| const controller = createController(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| controller.setFlagOverride('flag1', 'value1'); | ||||||||||||||||||||||||||
| controller.setFlagOverride('flag2', 'value2'); | ||||||||||||||||||||||||||
|
Comment on lines
+718
to
+721
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar:
Suggested change
|
||||||||||||||||||||||||||
| controller.clearAllFlagOverrides(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state.localOverrides).toStrictEqual({}); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| it('does not affect state when no overrides exist', () => { | ||||||||||||||||||||||||||
| const controller = createController(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| controller.clearAllFlagOverrides(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| expect(controller.state.localOverrides).toStrictEqual({}); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| describe('integration with remote flags', () => { | ||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that with these changes we are splitting up the tests for |
||||||||||||||||||||||||||
| it('preserves overrides when remote flags are updated', async () => { | ||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a large number of steps represented here for what I think ought to be a simple test (given my reading of the logic). Similar to other suggestions I've made, is it enough to set up the initial state instead of having to call a few methods?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated |
||||||||||||||||||||||||||
| const clientConfigApiService = buildClientConfigApiService({ | ||||||||||||||||||||||||||
| remoteFeatureFlags: { remoteFlag: 'initialRemoteValue' }, | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| const controller = createController({ clientConfigApiService }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Set overrides before fetching remote flags | ||||||||||||||||||||||||||
| controller.setFlagOverride('overrideFlag', 'overrideValue'); | ||||||||||||||||||||||||||
| controller.setFlagOverride('remoteFlag', 'updatedRemoteValue'); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| await controller.updateRemoteFeatureFlags(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Overrides should be preserved when remote flags are updated. | ||||||||||||||||||||||||||
| expect(controller.state.localOverrides).toStrictEqual({ | ||||||||||||||||||||||||||
| overrideFlag: 'overrideValue', | ||||||||||||||||||||||||||
| remoteFlag: 'updatedRemoteValue', | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| describe('metadata', () => { | ||||||||||||||||||||||||||
| it('includes expected state in debug snapshots', () => { | ||||||||||||||||||||||||||
| const controller = createController(); | ||||||||||||||||||||||||||
|
|
@@ -658,6 +768,8 @@ describe('RemoteFeatureFlagController', () => { | |||||||||||||||||||||||||
| ).toMatchInlineSnapshot(` | ||||||||||||||||||||||||||
| Object { | ||||||||||||||||||||||||||
| "cacheTimestamp": 0, | ||||||||||||||||||||||||||
| "localOverrides": Object {}, | ||||||||||||||||||||||||||
| "rawRemoteFeatureFlags": Object {}, | ||||||||||||||||||||||||||
| "remoteFeatureFlags": Object {}, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| `); | ||||||||||||||||||||||||||
|
|
@@ -675,6 +787,8 @@ describe('RemoteFeatureFlagController', () => { | |||||||||||||||||||||||||
| ).toMatchInlineSnapshot(` | ||||||||||||||||||||||||||
| Object { | ||||||||||||||||||||||||||
| "cacheTimestamp": 0, | ||||||||||||||||||||||||||
| "localOverrides": Object {}, | ||||||||||||||||||||||||||
| "rawRemoteFeatureFlags": Object {}, | ||||||||||||||||||||||||||
| "remoteFeatureFlags": Object {}, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| `); | ||||||||||||||||||||||||||
|
|
@@ -692,6 +806,8 @@ describe('RemoteFeatureFlagController', () => { | |||||||||||||||||||||||||
| ).toMatchInlineSnapshot(` | ||||||||||||||||||||||||||
| Object { | ||||||||||||||||||||||||||
| "cacheTimestamp": 0, | ||||||||||||||||||||||||||
| "localOverrides": Object {}, | ||||||||||||||||||||||||||
| "rawRemoteFeatureFlags": Object {}, | ||||||||||||||||||||||||||
| "remoteFeatureFlags": Object {}, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| `); | ||||||||||||||||||||||||||
|
|
@@ -708,6 +824,7 @@ describe('RemoteFeatureFlagController', () => { | |||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
| ).toMatchInlineSnapshot(` | ||||||||||||||||||||||||||
| Object { | ||||||||||||||||||||||||||
| "localOverrides": Object {}, | ||||||||||||||||||||||||||
| "remoteFeatureFlags": Object {}, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| `); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -21,13 +21,15 @@ import { isVersionFeatureFlag, getVersionData } from './utils/version'; | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // === GENERAL === | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const controllerName = 'RemoteFeatureFlagController'; | ||||||||||||||||||||||||||
| export const controllerName = 'RemoteFeatureFlagController'; | ||||||||||||||||||||||||||
| export const DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 1 day | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // === STATE === | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export type RemoteFeatureFlagControllerState = { | ||||||||||||||||||||||||||
| remoteFeatureFlags: FeatureFlags; | ||||||||||||||||||||||||||
| localOverrides: FeatureFlags; | ||||||||||||||||||||||||||
| rawRemoteFeatureFlags: FeatureFlags; | ||||||||||||||||||||||||||
| cacheTimestamp: number; | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -38,6 +40,18 @@ const remoteFeatureFlagControllerMetadata = { | |||||||||||||||||||||||||
| includeInDebugSnapshot: true, | ||||||||||||||||||||||||||
| usedInUi: true, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| localOverrides: { | ||||||||||||||||||||||||||
| includeInStateLogs: true, | ||||||||||||||||||||||||||
| persist: true, | ||||||||||||||||||||||||||
| includeInDebugSnapshot: true, | ||||||||||||||||||||||||||
| usedInUi: true, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| rawRemoteFeatureFlags: { | ||||||||||||||||||||||||||
| includeInStateLogs: true, | ||||||||||||||||||||||||||
| persist: true, | ||||||||||||||||||||||||||
| includeInDebugSnapshot: true, | ||||||||||||||||||||||||||
| usedInUi: false, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| cacheTimestamp: { | ||||||||||||||||||||||||||
| includeInStateLogs: true, | ||||||||||||||||||||||||||
| persist: true, | ||||||||||||||||||||||||||
|
|
@@ -62,9 +76,27 @@ export type RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction = { | |||||||||||||||||||||||||
| handler: RemoteFeatureFlagController['updateRemoteFeatureFlags']; | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export type RemoteFeatureFlagControllerSetFlagOverrideAction = { | ||||||||||||||||||||||||||
| type: `${typeof controllerName}:setFlagOverride`; | ||||||||||||||||||||||||||
| handler: RemoteFeatureFlagController['setFlagOverride']; | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export type RemoteFeatureFlagControllerRemoveFlagOverrideAction = { | ||||||||||||||||||||||||||
| type: `${typeof controllerName}:removeFlagOverride`; | ||||||||||||||||||||||||||
| handler: RemoteFeatureFlagController['removeFlagOverride']; | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export type RemoteFeatureFlagControllerClearAllFlagOverridesAction = { | ||||||||||||||||||||||||||
| type: `${typeof controllerName}:clearAllFlagOverrides`; | ||||||||||||||||||||||||||
| handler: RemoteFeatureFlagController['clearAllFlagOverrides']; | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export type RemoteFeatureFlagControllerActions = | ||||||||||||||||||||||||||
| | RemoteFeatureFlagControllerGetStateAction | ||||||||||||||||||||||||||
| | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction; | ||||||||||||||||||||||||||
| | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction | ||||||||||||||||||||||||||
| | RemoteFeatureFlagControllerSetFlagOverrideAction | ||||||||||||||||||||||||||
| | RemoteFeatureFlagControllerRemoveFlagOverrideAction | ||||||||||||||||||||||||||
| | RemoteFeatureFlagControllerClearAllFlagOverridesAction; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export type RemoteFeatureFlagControllerStateChangeEvent = | ||||||||||||||||||||||||||
| ControllerStateChangeEvent< | ||||||||||||||||||||||||||
|
|
@@ -89,6 +121,8 @@ export type RemoteFeatureFlagControllerMessenger = Messenger< | |||||||||||||||||||||||||
| export function getDefaultRemoteFeatureFlagControllerState(): RemoteFeatureFlagControllerState { | ||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||
| remoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| localOverrides: {}, | ||||||||||||||||||||||||||
| rawRemoteFeatureFlags: {}, | ||||||||||||||||||||||||||
| cacheTimestamp: 0, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
@@ -218,6 +252,8 @@ export class RemoteFeatureFlagController extends BaseController< | |||||||||||||||||||||||||
| this.update(() => { | ||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||
| remoteFeatureFlags: processedRemoteFeatureFlags, | ||||||||||||||||||||||||||
| localOverrides: this.state.localOverrides, | ||||||||||||||||||||||||||
| rawRemoteFeatureFlags: remoteFeatureFlags, | ||||||||||||||||||||||||||
cursor[bot] marked this conversation as resolved.
Show resolved
Hide resolved
asalsys marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
| cacheTimestamp: Date.now(), | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
Comment on lines
252
to
258
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps this is slightly out of scope for this PR, but instead of having to remember to update this list each time a new state property is added, it would be better to only change the state properties we want:
Suggested change
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this doesn't work, would it at least be better to spread |
||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
|
@@ -291,4 +327,50 @@ export class RemoteFeatureFlagController extends BaseController< | |||||||||||||||||||||||||
| disable(): void { | ||||||||||||||||||||||||||
| this.#disabled = true; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Sets a local override for a specific feature flag. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * @param flagName - The name of the feature flag to override. | ||||||||||||||||||||||||||
| * @param value - The override value for the feature flag. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| setFlagOverride(flagName: string, value: Json): void { | ||||||||||||||||||||||||||
| this.update(() => { | ||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||
| ...this.state, | ||||||||||||||||||||||||||
| localOverrides: { | ||||||||||||||||||||||||||
| ...this.state.localOverrides, | ||||||||||||||||||||||||||
| [flagName]: value, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Clears the local override for a specific feature flag. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * @param flagName - The name of the feature flag to clear. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| removeFlagOverride(flagName: string): void { | ||||||||||||||||||||||||||
| const newLocalOverrides = { ...this.state.localOverrides }; | ||||||||||||||||||||||||||
| delete newLocalOverrides[flagName]; | ||||||||||||||||||||||||||
| this.update(() => { | ||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||
| ...this.state, | ||||||||||||||||||||||||||
| localOverrides: newLocalOverrides, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||
| * Clears all local feature flag overrides. | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| clearAllFlagOverrides(): void { | ||||||||||||||||||||||||||
| this.update(() => { | ||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||
| ...this.state, | ||||||||||||||||||||||||||
| localOverrides: {}, | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this covered by "Add new controller state properties"? Perhaps we don't need it.