diff --git a/.changeset/eager-toes-rest.md b/.changeset/eager-toes-rest.md new file mode 100644 index 0000000000..ce9764574c --- /dev/null +++ b/.changeset/eager-toes-rest.md @@ -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. diff --git a/docs/plugins/feature-flags.md b/docs/plugins/feature-flags.md index e9e000df0d..2d0e34ba4b 100644 --- a/docs/plugins/feature-flags.md +++ b/docs/plugins/feature-flags.md @@ -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 diff --git a/packages/core-app-api/src/app/AppManager.tsx b/packages/core-app-api/src/app/AppManager.tsx index e1a83a79b7..4f0d2b2d4d 100644 --- a/packages/core-app-api/src/app/AppManager.tsx +++ b/packages/core-app-api/src/app/AppManager.tsx @@ -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(), }); } diff --git a/packages/core-plugin-api/report.api.md b/packages/core-plugin-api/report.api.md index 41887f7e63..654bbe94d1 100644 --- a/packages/core-plugin-api/report.api.md +++ b/packages/core-plugin-api/report.api.md @@ -500,6 +500,7 @@ export type PluginConfig< // @public export type PluginFeatureFlagConfig = { name: string; + description?: string; }; export { ProfileInfo }; diff --git a/packages/core-plugin-api/src/plugin/types.ts b/packages/core-plugin-api/src/plugin/types.ts index 3ba7706e16..057f493530 100644 --- a/packages/core-plugin-api/src/plugin/types.ts +++ b/packages/core-plugin-api/src/plugin/types.ts @@ -73,6 +73,8 @@ export type BackstagePlugin< export type PluginFeatureFlagConfig = { /** Feature flag name */ name: string; + /** Feature flag description */ + description?: string; }; /** diff --git a/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx b/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx index e21befc80e..51c31aca25 100644 --- a/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createSpecializedApp.test.tsx @@ -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 { diff --git a/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx b/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx index 680ba6dce5..fda00b70b1 100644 --- a/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx +++ b/packages/frontend-app-api/src/wiring/createSpecializedApp.tsx @@ -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, }), ); diff --git a/packages/frontend-plugin-api/report.api.md b/packages/frontend-plugin-api/report.api.md index d925be726f..4624e68dda 100644 --- a/packages/frontend-plugin-api/report.api.md +++ b/packages/frontend-plugin-api/report.api.md @@ -1279,6 +1279,7 @@ export type FeatureFlag = { // @public export type FeatureFlagConfig = { name: string; + description?: string; }; // @public diff --git a/packages/frontend-plugin-api/src/wiring/types.ts b/packages/frontend-plugin-api/src/wiring/types.ts index d462803820..39f0c5b03c 100644 --- a/packages/frontend-plugin-api/src/wiring/types.ts +++ b/packages/frontend-plugin-api/src/wiring/types.ts @@ -29,6 +29,8 @@ import { FrontendPlugin } from './createFrontendPlugin'; export type FeatureFlagConfig = { /** Feature flag name */ name: string; + /** Feature flag description */ + description?: string; }; /** @public */