-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
improvement: allow to enable/disable content based on admin version (#…
…353) * improvement: allow to enable/disable content based on admin version * docs: add info about FeatureFlags and LocalStorage usage Signed-off-by: Nastya Rusina <[email protected]>
- Loading branch information
Showing
10 changed files
with
347 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { useAdminVersion } from 'components/hooks/useVersion'; | ||
import { AdminFlag, AdminVersion, baseAdminConfig } from './defaultConfig'; | ||
|
||
export const useIsEnabledInAdmin = (flag: AdminFlag): boolean => { | ||
const { adminVersion } = useAdminVersion(); | ||
if (!adminVersion || adminVersion === '') { | ||
return false; | ||
} | ||
|
||
// Split version to two array items - [Major][Minor.Patch] | ||
const versionSplit = adminVersion.replace(/\./, '&').split('&'); | ||
const curVersion: AdminVersion = { | ||
major: parseInt(versionSplit[0], 10) ?? 0, | ||
minor: parseFloat(versionSplit[1]) ?? 0.1, | ||
}; | ||
|
||
const requieredVersion = baseAdminConfig[flag] ?? null; | ||
// required version is less or equal current version - return true. | ||
if ( | ||
requieredVersion && | ||
(requieredVersion.major < curVersion.major || | ||
(requieredVersion.major === curVersion.major && requieredVersion.minor <= curVersion.minor)) | ||
) { | ||
return true; | ||
} | ||
|
||
return false; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
## Feature Flags | ||
|
||
We are using our internal feature flag solution to allow continuos integration, while features are in development. There are two types of flags: | ||
|
||
FeatureFlag: boolean flags which indicate if feature is enabled. | ||
AdminFlag: the minimal version of flyteadmin in which feature supported. | ||
All flags currently available could be found in /FeatureFlags/defaultConfig.ts file. Most of them under active development, which means we don't guarantee it will work as you expect. | ||
|
||
If you want to add your own flag, you need to add it to both enum FeatureFlag and defaultFlagConfig under production section. Initally all flags must be disabled, meaning you code path should not be executed by default | ||
|
||
**Example - adding flags:** | ||
|
||
```javascript | ||
enum FeatureFlags { | ||
... | ||
AddNewPage: 'add-new-page' | ||
UseCommonPath: 'use-common-path' | ||
} | ||
|
||
export const defaultFlagConfig: FeatureFlagConfig = { | ||
... | ||
'add-new-page': false, // default/prior behavior doesn't include new page | ||
'use-common-path': true, // default/prior behavior uses common path | ||
}; | ||
``` | ||
|
||
To use flags in code you need to ensure that the most top level component is wrapped by `FeatureFlagsProvider`. | ||
By default we are wrapping top component in Apps file, so if you do not plan to include | ||
feature flags checks in the `\*.tests.tsx` - you should be good to go. | ||
To check flag's value use `useFeatureFlag` hook. | ||
|
||
**Example - flag usage**: | ||
|
||
```javascript | ||
import { FeatureFlag, useFeatureFlag } from 'basics/FeatureFlags'; | ||
|
||
export function MyComponent(props: Props): React.ReactNode { | ||
... | ||
const isFlagEnabled = useFeatureFlag(FeatureFlag.AddNewPage); | ||
|
||
return isFlagEnabled ? <NewPage ...props/> : null; | ||
} | ||
``` | ||
|
||
During your local development you can either: | ||
|
||
- temporarily switch flags value in runtimeConfig as: | ||
```javascript | ||
let runtimeConfig = { | ||
...defaultFlagConfig, | ||
'add-new-page': true, | ||
}; | ||
``` | ||
- turn flag on/off from the devTools console in Chrome | ||
![SetFeatureFlagFromConsole](https://user-images.githubusercontent.com/55718143/150002962-f12bbe57-f221-4bbd-85e3-717aa0221e89.gif) | ||
|
||
#### Unit tests | ||
|
||
If you plan to test non-default flag value in your unit tests, make sure to wrap your component with `FeatureFlagsProvider`. | ||
Use `window.setFeatureFlag(flag, newValue)` function to set needed value and `window.clearRuntimeConfig()` | ||
to return to defaults. Beware to comment out/remove any changes in `runtimeConfig` during testing; | ||
|
||
```javascript | ||
function TestWrapper() { | ||
return <FeatureFlagsProvider> <TestContent /> </FeatureFlagsProvider> | ||
} | ||
|
||
describe('FeatureFlags', () => { | ||
afterEach(() => { | ||
window.clearRuntimeConfig(); // clean up flags | ||
}); | ||
|
||
it('Test', async () => { | ||
render(<TestWrapper />); | ||
|
||
window.setFeatureFlag(FeatureFlag.FlagInQuestion, true); | ||
await waitFor(() => { | ||
// check after flag changed value | ||
}); | ||
}); | ||
``` |
Oops, something went wrong.