Merge pull request #32061 from elaine-mattos/feat/add-description-plugin-feature-flags

feat(core-plugin-api): add optional description to plugin feature flags
This commit is contained in:
Andre Wanlin
2026-03-07 12:47:26 -06:00
committed by GitHub
9 changed files with 34 additions and 2 deletions
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/core-plugin-api': patch
'@backstage/core-app-api': patch
'@backstage/frontend-plugin-api': patch
'@backstage/frontend-app-api': patch
---
Add optional `description` field to plugin-level feature flags.
+8 -1
View File
@@ -19,11 +19,18 @@ import { createPlugin } from '@backstage/core-plugin-api';
export const examplePlugin = createPlugin({
// ...
featureFlags: [{ name: 'show-example-feature' }],
featureFlags: [
{
name: 'show-example-feature',
description: 'Enables the new beta dashboard view',
},
],
// ...
});
```
Note that the `description` property is optional. If not provided, the default "Registered in {pluginId} plugin" message is shown.
### In the application
Defining a feature flag in the application is done by adding feature flags in `featureFlags` array in the
@@ -341,6 +341,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be
for (const flag of plugin.getFeatureFlags()) {
featureFlagsApi.registerFlag({
name: flag.name,
description: flag.description,
pluginId: plugin.getId(),
});
}
+1
View File
@@ -500,6 +500,7 @@ export type PluginConfig<
// @public
export type PluginFeatureFlagConfig = {
name: string;
description?: string;
};
export { ProfileInfo };
@@ -73,6 +73,8 @@ export type BackstagePlugin<
export type PluginFeatureFlagConfig = {
/** Feature flag name */
name: string;
/** Feature flag description */
description?: string;
};
/**
@@ -103,7 +103,10 @@ describe('createSpecializedApp', () => {
features: [
createFrontendPlugin({
pluginId: 'test',
featureFlags: [{ name: 'a' }, { name: 'b' }],
featureFlags: [
{ name: 'a' },
{ name: 'b', description: 'Feature B description' },
],
extensions: [
createExtension({
attachTo: { id: 'root', input: 'app' },
@@ -146,6 +149,11 @@ describe('createSpecializedApp', () => {
expect(screen.getByText('flags:test=a,test=b')).toBeInTheDocument();
expect(flags).toEqual([
{ name: 'a', pluginId: 'test' },
{ name: 'b', pluginId: 'test', description: 'Feature B description' },
]);
expect(app.apis).toMatchInlineSnapshot(`
ApiResolver {
"apis": Map {
@@ -346,6 +346,7 @@ export function createSpecializedApp(options?: CreateSpecializedAppOptions): {
OpaqueFrontendPlugin.toInternal(feature).featureFlags.forEach(flag =>
featureFlagApi.registerFlag({
name: flag.name,
description: flag.description,
pluginId: feature.id,
}),
);
@@ -354,6 +355,7 @@ export function createSpecializedApp(options?: CreateSpecializedAppOptions): {
toInternalFrontendModule(feature).featureFlags.forEach(flag =>
featureFlagApi.registerFlag({
name: flag.name,
description: flag.description,
pluginId: feature.pluginId,
}),
);
@@ -1279,6 +1279,7 @@ export type FeatureFlag = {
// @public
export type FeatureFlagConfig = {
name: string;
description?: string;
};
// @public
@@ -29,6 +29,8 @@ import { FrontendPlugin } from './createFrontendPlugin';
export type FeatureFlagConfig = {
/** Feature flag name */
name: string;
/** Feature flag description */
description?: string;
};
/** @public */