Refactor toggling of featureFlags
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user