From 9511e9015aa45230b115ece52d399ec1b529c8f8 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 18 Dec 2025 22:41:40 -0300 Subject: [PATCH 1/6] Add alpha export with Backstage new frontend system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements #6421 - adds `/alpha` export path that uses Backstage's new declarative frontend system while maintaining backward compatibility with the existing legacy export. Changes: - Add `@backstage/frontend-plugin-api` dependency - Create `src/alpha.ts` with new frontend system plugin using: - EntityContentBlueprint for FlagsTab - EntityCardBlueprint for FlagsmithOverviewCard and FlagsmithUsageCard - Add exports and typesVersions configuration to package.json Usage: - Legacy: `import { flagsmithPlugin } from '@internal/plugin-flagsmith'` - Alpha: `import flagsmithPlugin from '@internal/plugin-flagsmith/alpha'` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- package.json | 11 +++++++++ src/alpha.ts | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/alpha.ts diff --git a/package.json b/package.json index 1434174..228a2c3 100644 --- a/package.json +++ b/package.json @@ -33,9 +33,20 @@ "backstage-cli package lint --fix" ] }, + "exports": { + ".": "./src/index.ts", + "./alpha": "./src/alpha.ts", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "alpha": ["src/alpha.ts"] + } + }, "dependencies": { "@backstage/core-components": "^0.18.2", "@backstage/core-plugin-api": "^1.11.1", + "@backstage/frontend-plugin-api": "^0.13.2", "@backstage/plugin-catalog-react": "^1.13.3", "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", diff --git a/src/alpha.ts b/src/alpha.ts new file mode 100644 index 0000000..8d282be --- /dev/null +++ b/src/alpha.ts @@ -0,0 +1,68 @@ +import { createElement } from 'react'; +import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; +import { + EntityContentBlueprint, + EntityCardBlueprint, +} from '@backstage/plugin-catalog-react/alpha'; + +/** + * Entity content (tab) for FlagsTab - displays feature flags for an entity + * Requires annotation: flagsmith.com/project-id + */ +const flagsTabContent = EntityContentBlueprint.make({ + name: 'flags', + params: { + path: '/flagsmith', + title: 'Feature Flags', + filter: 'has:annotation:flagsmith.com/project-id', + loader: () => + import('./components/FlagsTab').then(m => createElement(m.FlagsTab)), + }, +}); + +/** + * Entity card for FlagsmithOverviewCard - shows flag overview in entity page + * Requires annotation: flagsmith.com/project-id + */ +const overviewCard = EntityCardBlueprint.make({ + name: 'overview', + params: { + filter: 'has:annotation:flagsmith.com/project-id', + loader: () => + import('./components/FlagsmithOverviewCard').then(m => + createElement(m.FlagsmithOverviewCard), + ), + }, +}); + +/** + * Entity card for FlagsmithUsageCard - shows 30-day usage analytics + * Requires annotations: flagsmith.com/project-id, flagsmith.com/org-id + */ +const usageCard = EntityCardBlueprint.make({ + name: 'usage', + params: { + filter: 'has:annotation:flagsmith.com/project-id,flagsmith.com/org-id', + loader: () => + import('./components/FlagsmithUsageCard').then(m => + createElement(m.FlagsmithUsageCard), + ), + }, +}); + +/** + * Flagsmith plugin for Backstage's new frontend system. + * + * This is the alpha export of the Flagsmith plugin, implementing + * the new declarative frontend system. It provides: + * + * - Entity content tab showing feature flags + * - Overview card for entity pages + * - Usage analytics card + * + * @alpha + */ +export default createFrontendPlugin({ + pluginId: 'flagsmith', + extensions: [flagsTabContent, overviewCard, usageCard], +}); From c50659d73f760c6d418ed68e855b654cfdd25207 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Mon, 22 Dec 2025 21:56:28 -0300 Subject: [PATCH 2/6] refactor: remove legacy frontend system files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove plugin.ts, routes.ts, and plugin.test.ts that were part of the legacy Backstage frontend system using createPlugin API. BREAKING CHANGE: Legacy plugin export removed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/plugin.test.ts | 7 ------- src/plugin.ts | 22 ---------------------- src/routes.ts | 5 ----- 3 files changed, 34 deletions(-) delete mode 100644 src/plugin.test.ts delete mode 100644 src/plugin.ts delete mode 100644 src/routes.ts diff --git a/src/plugin.test.ts b/src/plugin.test.ts deleted file mode 100644 index 9fb5b58..0000000 --- a/src/plugin.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { flagsmithPlugin } from './plugin'; - -describe('flagsmith', () => { - it('should export plugin', () => { - expect(flagsmithPlugin).toBeDefined(); - }); -}); diff --git a/src/plugin.ts b/src/plugin.ts deleted file mode 100644 index b0eb4cd..0000000 --- a/src/plugin.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - createPlugin, - createComponentExtension, -} from '@backstage/core-plugin-api'; - -import { rootRouteRef } from './routes'; - -export const flagsmithPlugin = createPlugin({ - id: 'flagsmith', - routes: { - root: rootRouteRef, - }, -}); - -export const FlagsTab = flagsmithPlugin.provide( - createComponentExtension({ - name: 'FlagsTab', - component: { - lazy: () => import('./components/FlagsTab').then(m => m.FlagsTab), - }, - }), -); \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts deleted file mode 100644 index d31dbe2..0000000 --- a/src/routes.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createRouteRef } from '@backstage/core-plugin-api'; - -export const rootRouteRef = createRouteRef({ - id: 'flagsmith', -}); From fc414546bc9160ae87e040ca59ad80b208d0231e Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Mon, 22 Dec 2025 21:56:38 -0300 Subject: [PATCH 3/6] feat: make new frontend system the default export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate alpha.ts into index.ts as the main plugin export. The plugin now uses createFrontendPlugin with EntityContentBlueprint and EntityCardBlueprint from the new Backstage frontend system. Exports: - default: flagsmithPlugin (new frontend system) - flagsmithPlugin: named export for compatibility - FlagsTab, FlagsmithOverviewCard, FlagsmithUsageCard: components 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/alpha.ts | 68 ------------------------------------------------- src/index.ts | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 70 deletions(-) delete mode 100644 src/alpha.ts diff --git a/src/alpha.ts b/src/alpha.ts deleted file mode 100644 index 8d282be..0000000 --- a/src/alpha.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { createElement } from 'react'; -import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { - EntityContentBlueprint, - EntityCardBlueprint, -} from '@backstage/plugin-catalog-react/alpha'; - -/** - * Entity content (tab) for FlagsTab - displays feature flags for an entity - * Requires annotation: flagsmith.com/project-id - */ -const flagsTabContent = EntityContentBlueprint.make({ - name: 'flags', - params: { - path: '/flagsmith', - title: 'Feature Flags', - filter: 'has:annotation:flagsmith.com/project-id', - loader: () => - import('./components/FlagsTab').then(m => createElement(m.FlagsTab)), - }, -}); - -/** - * Entity card for FlagsmithOverviewCard - shows flag overview in entity page - * Requires annotation: flagsmith.com/project-id - */ -const overviewCard = EntityCardBlueprint.make({ - name: 'overview', - params: { - filter: 'has:annotation:flagsmith.com/project-id', - loader: () => - import('./components/FlagsmithOverviewCard').then(m => - createElement(m.FlagsmithOverviewCard), - ), - }, -}); - -/** - * Entity card for FlagsmithUsageCard - shows 30-day usage analytics - * Requires annotations: flagsmith.com/project-id, flagsmith.com/org-id - */ -const usageCard = EntityCardBlueprint.make({ - name: 'usage', - params: { - filter: 'has:annotation:flagsmith.com/project-id,flagsmith.com/org-id', - loader: () => - import('./components/FlagsmithUsageCard').then(m => - createElement(m.FlagsmithUsageCard), - ), - }, -}); - -/** - * Flagsmith plugin for Backstage's new frontend system. - * - * This is the alpha export of the Flagsmith plugin, implementing - * the new declarative frontend system. It provides: - * - * - Entity content tab showing feature flags - * - Overview card for entity pages - * - Usage analytics card - * - * @alpha - */ -export default createFrontendPlugin({ - pluginId: 'flagsmith', - extensions: [flagsTabContent, overviewCard, usageCard], -}); diff --git a/src/index.ts b/src/index.ts index 10b0056..63f1a1e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,72 @@ -// Frontend plugin exports -export { flagsmithPlugin, FlagsTab } from './plugin'; +import { createElement } from 'react'; +import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; +import { + EntityContentBlueprint, + EntityCardBlueprint, +} from '@backstage/plugin-catalog-react/alpha'; + +/** + * Entity content (tab) for FlagsTab - displays feature flags for an entity + * Requires annotation: flagsmith.com/project-id + */ +const flagsTabContent = EntityContentBlueprint.make({ + name: 'flags', + params: { + path: '/flagsmith', + title: 'Feature Flags', + filter: 'has:annotation:flagsmith.com/project-id', + loader: () => + import('./components/FlagsTab').then(m => createElement(m.FlagsTab)), + }, +}); + +/** + * Entity card for FlagsmithOverviewCard - shows flag overview in entity page + * Requires annotation: flagsmith.com/project-id + */ +const overviewCard = EntityCardBlueprint.make({ + name: 'overview', + params: { + filter: 'has:annotation:flagsmith.com/project-id', + loader: () => + import('./components/FlagsmithOverviewCard').then(m => + createElement(m.FlagsmithOverviewCard), + ), + }, +}); + +/** + * Entity card for FlagsmithUsageCard - shows 30-day usage analytics + * Requires annotations: flagsmith.com/project-id, flagsmith.com/org-id + */ +const usageCard = EntityCardBlueprint.make({ + name: 'usage', + params: { + filter: 'has:annotation:flagsmith.com/project-id,flagsmith.com/org-id', + loader: () => + import('./components/FlagsmithUsageCard').then(m => + createElement(m.FlagsmithUsageCard), + ), + }, +}); + +/** + * Flagsmith plugin for Backstage's new frontend system. + * + * This plugin provides: + * - Entity content tab showing feature flags + * - Overview card for entity pages + * - Usage analytics card + */ +const flagsmithPlugin = createFrontendPlugin({ + pluginId: 'flagsmith', + extensions: [flagsTabContent, overviewCard, usageCard], +}); + +export default flagsmithPlugin; +export { flagsmithPlugin }; + +// Export components for users who need direct access +export { FlagsTab } from './components/FlagsTab'; export { FlagsmithOverviewCard } from './components/FlagsmithOverviewCard'; export { FlagsmithUsageCard } from './components/FlagsmithUsageCard'; From 796e205f05b810b9b24f97ad6e27d47f627ae640 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Mon, 22 Dec 2025 21:56:59 -0300 Subject: [PATCH 4/6] chore: remove alpha export path from package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the separate /alpha export since the new frontend system is now the default export at the package root. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- package.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/package.json b/package.json index 228a2c3..5a5a587 100644 --- a/package.json +++ b/package.json @@ -35,14 +35,8 @@ }, "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.ts", "./package.json": "./package.json" }, - "typesVersions": { - "*": { - "alpha": ["src/alpha.ts"] - } - }, "dependencies": { "@backstage/core-components": "^0.18.2", "@backstage/core-plugin-api": "^1.11.1", From bf06364942d1ba9fd0ff1adf2c73f3994f919915 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Mon, 22 Dec 2025 21:57:41 -0300 Subject: [PATCH 5/6] fix(dev): update dev server for new frontend system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove registerPlugin call since the new frontend system plugin is not compatible with the legacy dev-utils registerPlugin API. Components are rendered directly via addPage instead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- dev/index.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev/index.tsx b/dev/index.tsx index ef2c4c7..b28047f 100644 --- a/dev/index.tsx +++ b/dev/index.tsx @@ -1,9 +1,9 @@ +import { PropsWithChildren } from 'react'; import { createDevApp } from '@backstage/dev-utils'; import { EntityProvider } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; import { setupWorker } from 'msw'; -import { PropsWithChildren } from 'react'; -import { flagsmithPlugin, FlagsTab, FlagsmithOverviewCard, FlagsmithUsageCard } from '../src'; +import { FlagsTab, FlagsmithOverviewCard, FlagsmithUsageCard } from '../src'; import { handlers } from './mockHandlers'; // Start MSW worker for API mocking @@ -37,7 +37,6 @@ const EntityWrapper = ({ children }: PropsWithChildren<{}>) => ( ); createDevApp() - .registerPlugin(flagsmithPlugin) .addPage({ element: ( From 74f66798e4f9d474508e152b42e071e6d1c74b06 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Mon, 22 Dec 2025 22:43:00 -0300 Subject: [PATCH 6/6] refactor: remove component exports from index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep only the default plugin export. The new frontend system handles component registration via blueprints automatically. Dev server now imports components directly from their files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- dev/index.tsx | 4 +++- src/index.ts | 6 ------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/dev/index.tsx b/dev/index.tsx index b28047f..ba4ef60 100644 --- a/dev/index.tsx +++ b/dev/index.tsx @@ -3,7 +3,9 @@ import { createDevApp } from '@backstage/dev-utils'; import { EntityProvider } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; import { setupWorker } from 'msw'; -import { FlagsTab, FlagsmithOverviewCard, FlagsmithUsageCard } from '../src'; +import { FlagsTab } from '../src/components/FlagsTab'; +import { FlagsmithOverviewCard } from '../src/components/FlagsmithOverviewCard'; +import { FlagsmithUsageCard } from '../src/components/FlagsmithUsageCard'; import { handlers } from './mockHandlers'; // Start MSW worker for API mocking diff --git a/src/index.ts b/src/index.ts index 63f1a1e..8b080d8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -64,9 +64,3 @@ const flagsmithPlugin = createFrontendPlugin({ }); export default flagsmithPlugin; -export { flagsmithPlugin }; - -// Export components for users who need direct access -export { FlagsTab } from './components/FlagsTab'; -export { FlagsmithOverviewCard } from './components/FlagsmithOverviewCard'; -export { FlagsmithUsageCard } from './components/FlagsmithUsageCard';