Refactor toggling of featureFlags

This commit is contained in:
Marcus Eide
2020-09-22 13:24:03 +02:00
parent a1ec478639
commit a942d42008
5 changed files with 89 additions and 63 deletions
@@ -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<FeatureFlagsApi>({
id: 'core.featureflags',
description: 'Used to toggle functionality in features across Backstage',
+1 -1
View File
@@ -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';
+5 -5
View File
@@ -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<FeatureFlagName, FeatureFlagState> {
* 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<FeatureFlagsRegistryItem> {
static from(entries: FeatureFlagsRegistryItem[]) {
@@ -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 (
<ListItem>
<ListItemText
primary={featureFlag.name}
secondary={`Registered in ${featureFlag.pluginId} plugin`}
/>
<ListItemSecondaryAction>
<ToggleButton
size="small"
value="flag"
selected={enabled}
onChange={toggleFlag}
>
<Tooltip placement="top" arrow title={enabled ? 'Disable' : 'Enable'}>
<CheckIcon />
</Tooltip>
</ToggleButton>
</ListItemSecondaryAction>
</ListItem>
);
};
export const FlagItem = ({ flag, enabled, toggleHandler }: Props) => (
<ListItem>
<ListItemText
primary={flag.name}
secondary={`Registered in ${flag.pluginId} plugin`}
/>
<ListItemSecondaryAction>
<ToggleButton
size="small"
value="flag"
selected={enabled}
onChange={() => toggleHandler(flag.name)}
>
<Tooltip placement="top" arrow title={enabled ? 'Disable' : 'Enable'}>
<CheckIcon />
</Tooltip>
</ToggleButton>
</ListItemSecondaryAction>
</ListItem>
);
@@ -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) => (
<List dense subheader={<ListSubheader>Feature Flags</ListSubheader>}>
{featureFlags.map(featureFlag => (
<FlagItem key={featureFlag.name} featureFlag={featureFlag} />
))}
</List>
);
export const FeatureFlagsList = ({ featureFlags }: Props) => {
const featureFlagApi = useApi(featureFlagsApiRef);
const [state, setState] = useState<Record<FeatureFlagName, FeatureFlagState>>(
{},
);
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 (
<List dense subheader={<ListSubheader>Feature Flags</ListSubheader>}>
{featureFlags.map(featureFlag => {
const enabled = Boolean(state[featureFlag.name]);
return (
<FlagItem
key={featureFlag.name}
flag={featureFlag}
enabled={enabled}
toggleHandler={toggleFlag}
/>
);
})}
</List>
);
};