From a942d42008be8dfb05e36a3b022ab7b2f3fe8e8f Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Tue, 22 Sep 2020 13:24:03 +0200 Subject: [PATCH] Refactor toggling of featureFlags --- .../src/apis/definitions/FeatureFlagsApi.ts | 12 ++-- packages/core-api/src/app/App.tsx | 2 +- packages/core-api/src/app/FeatureFlags.tsx | 10 +-- .../src/components/FeatureFlagsItem.tsx | 64 +++++++------------ .../src/components/FeatureFlagsList.tsx | 64 +++++++++++++++---- 5 files changed, 89 insertions(+), 63 deletions(-) diff --git a/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts b/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts index b6aac75620..dd9657d7d8 100644 --- a/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts +++ b/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts @@ -15,11 +15,8 @@ */ import { createApiRef } from '../ApiRef'; -import { - UserFlags, - FeatureFlagsRegistry, - FeatureFlagsRegistryItem, -} from '../../app/FeatureFlags'; +import { UserFlags, FeatureFlagsRegistry } from '../../app/FeatureFlags'; +import { FeatureFlagName } from '../../plugin'; /** * The feature flags API is used to toggle functionality to users across plugins and Backstage. @@ -55,6 +52,11 @@ export interface FeatureFlagsApi { getRegisteredFlags(): FeatureFlagsRegistry; } +export interface FeatureFlagsRegistryItem { + pluginId: string; + name: FeatureFlagName; +} + export const featureFlagsApiRef = createApiRef({ id: 'core.featureflags', description: 'Used to toggle functionality in features across Backstage', diff --git a/packages/core-api/src/app/App.tsx b/packages/core-api/src/app/App.tsx index 9dd2fb138f..c222c3c420 100644 --- a/packages/core-api/src/app/App.tsx +++ b/packages/core-api/src/app/App.tsx @@ -30,12 +30,12 @@ import { SignInPageProps, } from './types'; import { BackstagePlugin } from '../plugin'; -import { FeatureFlagsRegistryItem } from './FeatureFlags'; import { featureFlagsApiRef, AppThemeApi, ConfigApi, identityApiRef, + FeatureFlagsRegistryItem, } from '../apis/definitions'; import { AppThemeProvider } from './AppThemeProvider'; diff --git a/packages/core-api/src/app/FeatureFlags.tsx b/packages/core-api/src/app/FeatureFlags.tsx index 3db2a18a02..7a69fa5456 100644 --- a/packages/core-api/src/app/FeatureFlags.tsx +++ b/packages/core-api/src/app/FeatureFlags.tsx @@ -15,7 +15,11 @@ */ import { FeatureFlagName } from '../plugin/types'; -import { FeatureFlagState, FeatureFlagsApi } from '../apis/definitions'; +import { + FeatureFlagState, + FeatureFlagsApi, + FeatureFlagsRegistryItem, +} from '../apis/definitions'; /** * Helper method for validating compatibility and flag name. @@ -129,10 +133,6 @@ export class UserFlags extends Map { * This acts as a holding data structure for feature flags * that plugins wish to register for use in Backstage. */ -export interface FeatureFlagsRegistryItem { - pluginId: string; - name: FeatureFlagName; -} export class FeatureFlagsRegistry extends Array { static from(entries: FeatureFlagsRegistryItem[]) { diff --git a/plugins/user-settings/src/components/FeatureFlagsItem.tsx b/plugins/user-settings/src/components/FeatureFlagsItem.tsx index bc327061ef..760aa25a34 100644 --- a/plugins/user-settings/src/components/FeatureFlagsItem.tsx +++ b/plugins/user-settings/src/components/FeatureFlagsItem.tsx @@ -15,7 +15,6 @@ */ import React from 'react'; -import { FeatureFlagName, useApi, featureFlagsApiRef } from '@backstage/core'; import { ListItem, ListItemSecondaryAction, @@ -24,46 +23,31 @@ import { } from '@material-ui/core'; import CheckIcon from '@material-ui/icons/CheckCircle'; import { ToggleButton } from '@material-ui/lab'; - -export type Item = { - name: FeatureFlagName; - pluginId: string; -}; +import { FeatureFlagsRegistryItem } from '@backstage/core'; type Props = { - featureFlag: Item; + flag: FeatureFlagsRegistryItem; + enabled: boolean; + toggleHandler: Function; }; -export const FlagItem = ({ featureFlag }: Props) => { - const api = useApi(featureFlagsApiRef); - - const [enabled, setEnabled] = React.useState( - Boolean(api.getFlags().get(featureFlag.name)), - ); - - const toggleFlag = () => { - const newState = api.getFlags().toggle(featureFlag.name); - setEnabled(Boolean(newState)); - }; - - return ( - - - - - - - - - - - ); -}; +export const FlagItem = ({ flag, enabled, toggleHandler }: Props) => ( + + + + toggleHandler(flag.name)} + > + + + + + + +); diff --git a/plugins/user-settings/src/components/FeatureFlagsList.tsx b/plugins/user-settings/src/components/FeatureFlagsList.tsx index 5687446511..0d7404c6fd 100644 --- a/plugins/user-settings/src/components/FeatureFlagsList.tsx +++ b/plugins/user-settings/src/components/FeatureFlagsList.tsx @@ -14,19 +14,59 @@ * limitations under the License. */ -import React from 'react'; -import List from '@material-ui/core/List'; -import ListSubheader from '@material-ui/core/ListSubheader'; -import { FlagItem, Item } from './FeatureFlagsItem'; +import React, { useState, useEffect } from 'react'; +import { List, ListSubheader } from '@material-ui/core'; +import { + useApi, + featureFlagsApiRef, + FeatureFlagName, + FeatureFlagState, + FeatureFlagsRegistryItem, +} from '@backstage/core'; +import { FlagItem } from './FeatureFlagsItem'; type Props = { - featureFlags: Item[]; + featureFlags: FeatureFlagsRegistryItem[]; }; -export const FeatureFlagsList = ({ featureFlags }: Props) => ( - Feature Flags}> - {featureFlags.map(featureFlag => ( - - ))} - -); +export const FeatureFlagsList = ({ featureFlags }: Props) => { + const featureFlagApi = useApi(featureFlagsApiRef); + const [state, setState] = useState>( + {}, + ); + + useEffect(() => { + featureFlags.map(featureFlag => { + setState({ + [featureFlag.name]: featureFlagApi.getFlags().get(featureFlag.name), + }); + }); + }, [featureFlagApi, featureFlags]); + + const toggleFlag = (flagName: FeatureFlagName) => { + const newState = featureFlagApi.getFlags().toggle(flagName); + + setState(prevState => ({ + ...prevState, + [flagName]: newState, + })); + featureFlagApi.getFlags().save(); + }; + + return ( + Feature Flags}> + {featureFlags.map(featureFlag => { + const enabled = Boolean(state[featureFlag.name]); + + return ( + + ); + })} + + ); +};