From b8c71015c33889df89b4361f929af7e726e28107 Mon Sep 17 00:00:00 2001 From: Christoph Jerolimov Date: Thu, 18 Jun 2026 09:29:06 +0200 Subject: [PATCH 1/3] feat(app-defaults): add new app-defaults frontend module plugin Co-Authored-By: Claude Opus 4.6 Signed-off-by: Christoph Jerolimov --- .../app-defaults/packages/app/package.json | 1 + .../plugins/app-defaults/.eslintrc.js | 1 + .../plugins/app-defaults/README.md | 5 +++ .../plugins/app-defaults/package.json | 39 +++++++++++++++++++ .../plugins/app-defaults/src/index.ts | 16 ++++++++ .../plugins/app-defaults/src/module.tsx | 23 +++++++++++ .../plugins/app-defaults/src/setupTests.ts | 16 ++++++++ workspaces/app-defaults/yarn.lock | 11 ++++++ 8 files changed, 112 insertions(+) create mode 100644 workspaces/app-defaults/plugins/app-defaults/.eslintrc.js create mode 100644 workspaces/app-defaults/plugins/app-defaults/README.md create mode 100644 workspaces/app-defaults/plugins/app-defaults/package.json create mode 100644 workspaces/app-defaults/plugins/app-defaults/src/index.ts create mode 100644 workspaces/app-defaults/plugins/app-defaults/src/module.tsx create mode 100644 workspaces/app-defaults/plugins/app-defaults/src/setupTests.ts diff --git a/workspaces/app-defaults/packages/app/package.json b/workspaces/app-defaults/packages/app/package.json index 4a4efb1440..1ef90e7755 100644 --- a/workspaces/app-defaults/packages/app/package.json +++ b/workspaces/app-defaults/packages/app/package.json @@ -46,6 +46,7 @@ "@mui/material": "^5.18.0", "@red-hat-developer-hub/backstage-plugin-app-auth": "workspace:^", "@red-hat-developer-hub/backstage-plugin-app-integrations": "workspace:^", + "@red-hat-developer-hub/backstage-plugin-app-defaults": "workspace:^", "@red-hat-developer-hub/backstage-plugin-app-react": "workspace:^", "@red-hat-developer-hub/backstage-plugin-global-header": "^1.21.0", "material-icons": "^1.13.14", diff --git a/workspaces/app-defaults/plugins/app-defaults/.eslintrc.js b/workspaces/app-defaults/plugins/app-defaults/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/workspaces/app-defaults/plugins/app-defaults/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/workspaces/app-defaults/plugins/app-defaults/README.md b/workspaces/app-defaults/plugins/app-defaults/README.md new file mode 100644 index 0000000000..61fe707b89 --- /dev/null +++ b/workspaces/app-defaults/plugins/app-defaults/README.md @@ -0,0 +1,5 @@ +# @red-hat-developer-hub/backstage-plugin-app-defaults + +The defaults frontend module for the app plugin. + +_This plugin was created through the Backstage CLI_ diff --git a/workspaces/app-defaults/plugins/app-defaults/package.json b/workspaces/app-defaults/plugins/app-defaults/package.json new file mode 100644 index 0000000000..edb886fab8 --- /dev/null +++ b/workspaces/app-defaults/plugins/app-defaults/package.json @@ -0,0 +1,39 @@ +{ + "name": "@red-hat-developer-hub/backstage-plugin-app-defaults", + "version": "0.1.0", + "license": "Apache-2.0", + "private": true, + "description": "The defaults frontend module for the app plugin.", + "main": "src/index.ts", + "types": "src/index.ts", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin-module", + "pluginId": "app", + "pluginPackage": "@backstage/plugin-app" + }, + "sideEffects": false, + "scripts": { + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/frontend-plugin-api": "^0.15.0" + }, + "devDependencies": { + "@backstage/cli": "^0.36.0", + "@testing-library/jest-dom": "^6.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/workspaces/app-defaults/plugins/app-defaults/src/index.ts b/workspaces/app-defaults/plugins/app-defaults/src/index.ts new file mode 100644 index 0000000000..962acffc7f --- /dev/null +++ b/workspaces/app-defaults/plugins/app-defaults/src/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { appModuleDefaults as default } from './module'; diff --git a/workspaces/app-defaults/plugins/app-defaults/src/module.tsx b/workspaces/app-defaults/plugins/app-defaults/src/module.tsx new file mode 100644 index 0000000000..9c254d801b --- /dev/null +++ b/workspaces/app-defaults/plugins/app-defaults/src/module.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createFrontendModule } from '@backstage/frontend-plugin-api'; + +export const appModuleDefaults = createFrontendModule({ + pluginId: 'app', + extensions: [ + /* TODO */ + ], +}); diff --git a/workspaces/app-defaults/plugins/app-defaults/src/setupTests.ts b/workspaces/app-defaults/plugins/app-defaults/src/setupTests.ts new file mode 100644 index 0000000000..b529814c42 --- /dev/null +++ b/workspaces/app-defaults/plugins/app-defaults/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@testing-library/jest-dom'; diff --git a/workspaces/app-defaults/yarn.lock b/workspaces/app-defaults/yarn.lock index 9c7d0400cb..926af1320d 100644 --- a/workspaces/app-defaults/yarn.lock +++ b/workspaces/app-defaults/yarn.lock @@ -11252,6 +11252,16 @@ __metadata: languageName: unknown linkType: soft +"@red-hat-developer-hub/backstage-plugin-app-defaults@workspace:^, @red-hat-developer-hub/backstage-plugin-app-defaults@workspace:plugins/app-module-defaults": + version: 0.0.0-use.local + resolution: "@red-hat-developer-hub/backstage-plugin-app-defaults@workspace:plugins/app-module-defaults" + dependencies: + "@backstage/cli": "npm:^0.36.0" + "@backstage/frontend-plugin-api": "npm:^0.15.0" + "@testing-library/jest-dom": "npm:^6.0.0" + languageName: unknown + linkType: soft + "@red-hat-developer-hub/backstage-plugin-app-react@workspace:^, @red-hat-developer-hub/backstage-plugin-app-react@workspace:plugins/app-react": version: 0.0.0-use.local resolution: "@red-hat-developer-hub/backstage-plugin-app-react@workspace:plugins/app-react" @@ -15974,6 +15984,7 @@ __metadata: "@playwright/test": "npm:^1.58.2" "@red-hat-developer-hub/backstage-plugin-app-auth": "workspace:^" "@red-hat-developer-hub/backstage-plugin-app-integrations": "workspace:^" + "@red-hat-developer-hub/backstage-plugin-app-defaults": "workspace:^" "@red-hat-developer-hub/backstage-plugin-app-react": "workspace:^" "@red-hat-developer-hub/backstage-plugin-global-header": "npm:^1.21.0" "@testing-library/dom": "npm:^10.0.0" From d1f739572fd32c7d8973e0aae9d894968565004e Mon Sep 17 00:00:00 2001 From: Christoph Jerolimov Date: Thu, 18 Jun 2026 12:02:11 +0200 Subject: [PATCH 2/3] feat(app-defaults): move drawer extension from app-react to app-defaults Move ApplicationDrawer and DrawerPanel components into app-defaults and re-export appDrawerExtensions from the new module. The app-react package now only exposes the public API surface (hooks, blueprints, data refs, types) while app-defaults owns the concrete extension wiring. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Christoph Jerolimov --- .../app-defaults/packages/app/knip-report.md | 11 +- .../app-defaults/packages/app/package.json | 2 +- .../app-defaults/packages/app/src/App.tsx | 4 +- .../app/src/modules/drawer-demo/index.tsx | 2 +- .../plugins/app-auth/knip-report.md | 9 ++ .../plugins/app-defaults/README.md | 78 +++++++++++++- .../plugins/app-defaults/knip-report.md | 2 + .../plugins/app-defaults/package.json | 16 ++- .../plugins/app-defaults/report.api.md | 56 ++++++++++ .../components/ApplicationDrawer.test.tsx | 9 +- .../drawer/components/ApplicationDrawer.tsx | 5 +- .../drawer/components/DrawerPanel.test.tsx | 0 .../src/drawer/components/DrawerPanel.tsx | 0 .../src/drawer/extensions.tsx} | 29 ++--- .../src/drawer/index.ts} | 8 +- .../plugins/app-defaults/src/index.ts | 4 +- .../plugins/app-defaults/src/module.tsx | 10 +- .../plugins/app-integrations/knip-report.md | 9 ++ .../app-defaults/plugins/app-react/README.md | 42 ++------ .../plugins/app-react/knip-report.md | 8 +- .../plugins/app-react/package.json | 20 +--- .../plugins/app-react/report-alpha.api.md | 100 ------------------ .../extensions/AppDrawerContentBlueprint.ts | 2 +- .../extensions/appDrawerContentDataRef.ts | 2 +- .../plugins/app-react/src/drawer/index.ts | 10 +- .../plugins/app-react/src/index.ts | 7 +- workspaces/app-defaults/yarn.lock | 31 +++--- 27 files changed, 234 insertions(+), 242 deletions(-) create mode 100644 workspaces/app-defaults/plugins/app-auth/knip-report.md create mode 100644 workspaces/app-defaults/plugins/app-defaults/knip-report.md create mode 100644 workspaces/app-defaults/plugins/app-defaults/report.api.md rename workspaces/app-defaults/plugins/{app-react => app-defaults}/src/drawer/components/ApplicationDrawer.test.tsx (94%) rename workspaces/app-defaults/plugins/{app-react => app-defaults}/src/drawer/components/ApplicationDrawer.tsx (94%) rename workspaces/app-defaults/plugins/{app-react => app-defaults}/src/drawer/components/DrawerPanel.test.tsx (100%) rename workspaces/app-defaults/plugins/{app-react => app-defaults}/src/drawer/components/DrawerPanel.tsx (100%) rename workspaces/app-defaults/plugins/{app-react/src/drawer/extensions/appDrawerModule.tsx => app-defaults/src/drawer/extensions.tsx} (64%) rename workspaces/app-defaults/plugins/{app-react/src/alpha.ts => app-defaults/src/drawer/index.ts} (82%) create mode 100644 workspaces/app-defaults/plugins/app-integrations/knip-report.md delete mode 100644 workspaces/app-defaults/plugins/app-react/report-alpha.api.md diff --git a/workspaces/app-defaults/packages/app/knip-report.md b/workspaces/app-defaults/packages/app/knip-report.md index c12221a219..c1411b3d7b 100644 --- a/workspaces/app-defaults/packages/app/knip-report.md +++ b/workspaces/app-defaults/packages/app/knip-report.md @@ -16,14 +16,13 @@ | @backstage/plugin-techdocs | package.json:40:6 | error | | @backstage/plugin-signals | package.json:39:6 | error | | @backstage/plugin-org | package.json:36:6 | error | -| react-router | package.json:50:6 | error | +| react-router | package.json:55:6 | error | -## Unused devDependencies (4) +## Unused devDependencies (3) | Name | Location | Severity | | :----------------------------- | :---------------- | :------- | -| @backstage/frontend-test-utils | package.json:54:6 | error | -| @testing-library/user-event | package.json:59:6 | error | -| @testing-library/dom | package.json:56:6 | error | -| cross-env | package.json:61:6 | error | +| @backstage/frontend-test-utils | package.json:59:6 | error | +| @testing-library/user-event | package.json:64:6 | error | +| cross-env | package.json:66:6 | error | diff --git a/workspaces/app-defaults/packages/app/package.json b/workspaces/app-defaults/packages/app/package.json index 1ef90e7755..fca84a368f 100644 --- a/workspaces/app-defaults/packages/app/package.json +++ b/workspaces/app-defaults/packages/app/package.json @@ -45,8 +45,8 @@ "@material-ui/icons": "^4.9.1", "@mui/material": "^5.18.0", "@red-hat-developer-hub/backstage-plugin-app-auth": "workspace:^", - "@red-hat-developer-hub/backstage-plugin-app-integrations": "workspace:^", "@red-hat-developer-hub/backstage-plugin-app-defaults": "workspace:^", + "@red-hat-developer-hub/backstage-plugin-app-integrations": "workspace:^", "@red-hat-developer-hub/backstage-plugin-app-react": "workspace:^", "@red-hat-developer-hub/backstage-plugin-global-header": "^1.21.0", "material-icons": "^1.13.14", diff --git a/workspaces/app-defaults/packages/app/src/App.tsx b/workspaces/app-defaults/packages/app/src/App.tsx index b33c137370..73742e474c 100644 --- a/workspaces/app-defaults/packages/app/src/App.tsx +++ b/workspaces/app-defaults/packages/app/src/App.tsx @@ -18,7 +18,7 @@ import { createApp } from '@backstage/frontend-defaults'; import catalogPlugin from '@backstage/plugin-catalog/alpha'; import { appAuthModule } from '@red-hat-developer-hub/backstage-plugin-app-auth/alpha'; import { appIntegrationsModule } from '@red-hat-developer-hub/backstage-plugin-app-integrations/alpha'; -import { appDrawerModule } from '@red-hat-developer-hub/backstage-plugin-app-react/alpha'; +import appDefaultsModule from '@red-hat-developer-hub/backstage-plugin-app-defaults'; import { globalHeaderModule, globalHeaderTranslationsModule, @@ -32,7 +32,7 @@ export default createApp({ navModule, appAuthModule, appIntegrationsModule, - appDrawerModule, + appDefaultsModule, drawerDemoModule, globalHeaderModule, globalHeaderTranslationsModule, diff --git a/workspaces/app-defaults/packages/app/src/modules/drawer-demo/index.tsx b/workspaces/app-defaults/packages/app/src/modules/drawer-demo/index.tsx index 57729eae16..2c69b792ae 100644 --- a/workspaces/app-defaults/packages/app/src/modules/drawer-demo/index.tsx +++ b/workspaces/app-defaults/packages/app/src/modules/drawer-demo/index.tsx @@ -15,7 +15,7 @@ */ import { createFrontendModule } from '@backstage/frontend-plugin-api'; -import { AppDrawerContentBlueprint } from '@red-hat-developer-hub/backstage-plugin-app-react/alpha'; +import { AppDrawerContentBlueprint } from '@red-hat-developer-hub/backstage-plugin-app-react'; import { GlobalHeaderMenuItemBlueprint } from '@red-hat-developer-hub/backstage-plugin-global-header/alpha'; import { ChatDrawerContent, diff --git a/workspaces/app-defaults/plugins/app-auth/knip-report.md b/workspaces/app-defaults/plugins/app-auth/knip-report.md new file mode 100644 index 0000000000..75193f481e --- /dev/null +++ b/workspaces/app-defaults/plugins/app-auth/knip-report.md @@ -0,0 +1,9 @@ +# Knip report + +## Unused devDependencies (2) + +| Name | Location | Severity | +| :--------------------- | :---------------- | :------- | +| @testing-library/react | package.json:64:6 | error | +| @backstage/test-utils | package.json:62:6 | error | + diff --git a/workspaces/app-defaults/plugins/app-defaults/README.md b/workspaces/app-defaults/plugins/app-defaults/README.md index 61fe707b89..e08a385d7d 100644 --- a/workspaces/app-defaults/plugins/app-defaults/README.md +++ b/workspaces/app-defaults/plugins/app-defaults/README.md @@ -1,5 +1,79 @@ # @red-hat-developer-hub/backstage-plugin-app-defaults -The defaults frontend module for the app plugin. +Defaults app plugin extensions for RHDH. Provides the application drawer system +that lets plugins contribute persistent side panels with host-owned state. -_This plugin was created through the Backstage CLI_ +## Installation + +Add the package as a dependency in your app: + +```bash +yarn add @red-hat-developer-hub/backstage-plugin-app-default +``` + +## App Integration + +Register the `appDefaults` module, or just the drawer module in your app's `createApp` call: + +```typescript +import { createApp } from '@backstage/frontend-defaults'; +import appDefaultsModule from '@red-hat-developer-hub/backstage-plugin-app-defaults'; + +export default createApp({ + features: [ + appDefaultsModule, + // ...other plugins and modules + ], +}); +``` + +Alternative you can install exported extensions yourself: + +```typescript +import { createApp } from '@backstage/frontend-defaults'; +import { appDrawerExtensions } from '@red-hat-developer-hub/backstage-plugin-app-defaults'; + +export const appExtensions = createFrontendModule({ + pluginId: 'app', + extensions: [...appDrawerExtensions], +}); + +export default createApp({ + features: [ + appExtensions, + // ...other plugins and modules + ], +}); +``` + +## Drawer + +### Added extension + +This app module registers an app wrapper extension (`app-root-wrapper:app/drawer`) +that renders the `ApplicationDrawer` around the app content and accepts drawer +content contributions via inputs. + +The drawer state is managed by a global singleton store. `useAppDrawer()` from +`@red-hat-developer-hub/backstage-plugin-app-react` will work from anywhere +in the React tree without a wrapping provider. + +See `@red-hat-developer-hub/backstage-plugin-app-react` for more information +how to contribute a plugin drawer and how to control (open, close, toggle) +drawers. + +### App-Config Overrides + +Deployers can override `defaultWidth`, `resizable`, and `priority` per-drawer in +`app-config.yaml` without changing plugin code. Config values take precedence +over the `params` set in code: + +```yaml +app: + extensions: + - app-drawer-content:my-plugin/my-drawer: + config: + defaultWidth: 600 + resizable: false + priority: 10 +``` diff --git a/workspaces/app-defaults/plugins/app-defaults/knip-report.md b/workspaces/app-defaults/plugins/app-defaults/knip-report.md new file mode 100644 index 0000000000..2661c35327 --- /dev/null +++ b/workspaces/app-defaults/plugins/app-defaults/knip-report.md @@ -0,0 +1,2 @@ +# Knip report + diff --git a/workspaces/app-defaults/plugins/app-defaults/package.json b/workspaces/app-defaults/plugins/app-defaults/package.json index edb886fab8..95cfaa779b 100644 --- a/workspaces/app-defaults/plugins/app-defaults/package.json +++ b/workspaces/app-defaults/plugins/app-defaults/package.json @@ -1,9 +1,8 @@ { "name": "@red-hat-developer-hub/backstage-plugin-app-defaults", - "version": "0.1.0", + "version": "0.0.0", "license": "Apache-2.0", - "private": true, - "description": "The defaults frontend module for the app plugin.", + "description": "Defaults app plugin extensions for RHDH (for now just a Drawer extension).", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { @@ -27,11 +26,18 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/frontend-plugin-api": "^0.15.0" + "@backstage/frontend-plugin-api": "^0.15.0", + "@backstage/plugin-app-react": "^0.2.1", + "@mui/material": "5.18.0", + "@red-hat-developer-hub/backstage-plugin-app-react": "workspace:^" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" }, "devDependencies": { "@backstage/cli": "^0.36.0", - "@testing-library/jest-dom": "^6.0.0" + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^16.0.0" }, "files": [ "dist" diff --git a/workspaces/app-defaults/plugins/app-defaults/report.api.md b/workspaces/app-defaults/plugins/app-defaults/report.api.md new file mode 100644 index 0000000000..1af9097325 --- /dev/null +++ b/workspaces/app-defaults/plugins/app-defaults/report.api.md @@ -0,0 +1,56 @@ +## API Report File for "@red-hat-developer-hub/backstage-plugin-app-defaults" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { AppDrawerContent } from '@red-hat-developer-hub/backstage-plugin-app-react'; +import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { ExtensionInput } from '@backstage/frontend-plugin-api'; +import { FrontendModule } from '@backstage/frontend-plugin-api'; +import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api'; +import { ReactNode } from 'react'; + +// Warning: (ae-missing-release-tag) "appDefaults" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +const appDefaults: FrontendModule; +export { appDefaults }; +export default appDefaults; + +// Warning: (ae-missing-release-tag) "appDrawerExtensions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const appDrawerExtensions: OverridableExtensionDefinition<{ + config: {}; + configInput: {}; + output: ExtensionDataRef< + (props: { children: ReactNode }) => JSX.Element | null, + 'app.root.wrapper', + {} + >; + inputs: { + drawers: ExtensionInput< + ConfigurableExtensionDataRef, + { + singleton: false; + optional: false; + internal: false; + } + >; + }; + kind: 'app-root-wrapper'; + name: 'drawer'; + params: { + Component?: [error: 'Use the `component` parameter instead']; + component: (props: { children: ReactNode }) => JSX.Element | null; + }; +}>[]; + +// Warnings were encountered during analysis: +// +// src/drawer/extensions.d.ts:30:22 - (ae-undocumented) Missing documentation for "appDrawerExtensions". +// src/module.d.ts:2:22 - (ae-undocumented) Missing documentation for "appDefaults". + +// (No @packageDocumentation comment for this package) +``` diff --git a/workspaces/app-defaults/plugins/app-react/src/drawer/components/ApplicationDrawer.test.tsx b/workspaces/app-defaults/plugins/app-defaults/src/drawer/components/ApplicationDrawer.test.tsx similarity index 94% rename from workspaces/app-defaults/plugins/app-react/src/drawer/components/ApplicationDrawer.test.tsx rename to workspaces/app-defaults/plugins/app-defaults/src/drawer/components/ApplicationDrawer.test.tsx index 315e96cfa5..de95c7c627 100644 --- a/workspaces/app-defaults/plugins/app-react/src/drawer/components/ApplicationDrawer.test.tsx +++ b/workspaces/app-defaults/plugins/app-defaults/src/drawer/components/ApplicationDrawer.test.tsx @@ -16,10 +16,13 @@ import { render, screen, act } from '@testing-library/react'; -import { useAppDrawer } from '../hooks/useAppDrawer'; -import { drawerStore } from '../utils/drawerStore'; +import { + useAppDrawer, + drawerStore, +} from '@red-hat-developer-hub/backstage-plugin-app-react'; +import type { AppDrawerContent } from '@red-hat-developer-hub/backstage-plugin-app-react'; + import { ApplicationDrawer } from './ApplicationDrawer'; -import type { AppDrawerContent } from '../types'; function OpenButton({ id }: { id: string }) { const { openDrawer } = useAppDrawer(); diff --git a/workspaces/app-defaults/plugins/app-react/src/drawer/components/ApplicationDrawer.tsx b/workspaces/app-defaults/plugins/app-defaults/src/drawer/components/ApplicationDrawer.tsx similarity index 94% rename from workspaces/app-defaults/plugins/app-react/src/drawer/components/ApplicationDrawer.tsx rename to workspaces/app-defaults/plugins/app-defaults/src/drawer/components/ApplicationDrawer.tsx index eba500ed8f..b4f2bf2101 100644 --- a/workspaces/app-defaults/plugins/app-react/src/drawer/components/ApplicationDrawer.tsx +++ b/workspaces/app-defaults/plugins/app-defaults/src/drawer/components/ApplicationDrawer.tsx @@ -16,9 +16,10 @@ import { useEffect, useRef } from 'react'; -import { useAppDrawer } from '../hooks/useAppDrawer'; +import { useAppDrawer } from '@red-hat-developer-hub/backstage-plugin-app-react'; +import type { AppDrawerContent } from '@red-hat-developer-hub/backstage-plugin-app-react'; + import { DrawerPanel } from './DrawerPanel'; -import type { AppDrawerContent } from '../types'; const DEFAULT_WIDTH = 500; diff --git a/workspaces/app-defaults/plugins/app-react/src/drawer/components/DrawerPanel.test.tsx b/workspaces/app-defaults/plugins/app-defaults/src/drawer/components/DrawerPanel.test.tsx similarity index 100% rename from workspaces/app-defaults/plugins/app-react/src/drawer/components/DrawerPanel.test.tsx rename to workspaces/app-defaults/plugins/app-defaults/src/drawer/components/DrawerPanel.test.tsx diff --git a/workspaces/app-defaults/plugins/app-react/src/drawer/components/DrawerPanel.tsx b/workspaces/app-defaults/plugins/app-defaults/src/drawer/components/DrawerPanel.tsx similarity index 100% rename from workspaces/app-defaults/plugins/app-react/src/drawer/components/DrawerPanel.tsx rename to workspaces/app-defaults/plugins/app-defaults/src/drawer/components/DrawerPanel.tsx diff --git a/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/appDrawerModule.tsx b/workspaces/app-defaults/plugins/app-defaults/src/drawer/extensions.tsx similarity index 64% rename from workspaces/app-defaults/plugins/app-react/src/drawer/extensions/appDrawerModule.tsx rename to workspaces/app-defaults/plugins/app-defaults/src/drawer/extensions.tsx index 0e91abc529..5809da2d10 100644 --- a/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/appDrawerModule.tsx +++ b/workspaces/app-defaults/plugins/app-defaults/src/drawer/extensions.tsx @@ -14,24 +14,23 @@ * limitations under the License. */ -import { - createExtensionInput, - createFrontendModule, -} from '@backstage/frontend-plugin-api'; +import { createExtensionInput } from '@backstage/frontend-plugin-api'; import { AppRootWrapperBlueprint } from '@backstage/plugin-app-react'; -import { ApplicationDrawer } from '../components/ApplicationDrawer'; -import { appDrawerContentDataRef } from './appDrawerContentDataRef'; +import { appDrawerContentDataRef } from '@red-hat-developer-hub/backstage-plugin-app-react'; + +import { ApplicationDrawer } from './components/ApplicationDrawer'; /** * Wrapper extension that renders the ApplicationDrawer around the app content. * * Uses AppRootWrapperBlueprint.makeWithOverrides to stay aligned with the * blueprint API while adding a custom `drawers` input for content extensions. - * Drawer state is managed by a global singleton store (see drawerStore.ts) - * rather than a React context provider. + * Drawer state is managed by a global singleton store. + * + * @public */ -const appDrawerExtension = AppRootWrapperBlueprint.makeWithOverrides({ +export const appDrawerExtension = AppRootWrapperBlueprint.makeWithOverrides({ name: 'drawer', inputs: { drawers: createExtensionInput([appDrawerContentDataRef]), @@ -46,14 +45,4 @@ const appDrawerExtension = AppRootWrapperBlueprint.makeWithOverrides({ }, }); -/** - * Frontend module that provides the app drawer system. - * Registers a wrapper extension that renders the drawer and accepts - * drawer content contributions via inputs. - * - * @alpha - */ -export const appDrawerModule = createFrontendModule({ - pluginId: 'app', - extensions: [appDrawerExtension], -}); +export const appDrawerExtensions = [appDrawerExtension]; diff --git a/workspaces/app-defaults/plugins/app-react/src/alpha.ts b/workspaces/app-defaults/plugins/app-defaults/src/drawer/index.ts similarity index 82% rename from workspaces/app-defaults/plugins/app-react/src/alpha.ts rename to workspaces/app-defaults/plugins/app-defaults/src/drawer/index.ts index 929f991052..4f86f003bd 100644 --- a/workspaces/app-defaults/plugins/app-react/src/alpha.ts +++ b/workspaces/app-defaults/plugins/app-defaults/src/drawer/index.ts @@ -14,10 +14,4 @@ * limitations under the License. */ -/** - * New Frontend System extension APIs for the RHDH app shell. - * - * @packageDocumentation - */ - -export * from './drawer'; +export { appDrawerExtensions } from './extensions'; diff --git a/workspaces/app-defaults/plugins/app-defaults/src/index.ts b/workspaces/app-defaults/plugins/app-defaults/src/index.ts index 962acffc7f..6a3d9f0cbc 100644 --- a/workspaces/app-defaults/plugins/app-defaults/src/index.ts +++ b/workspaces/app-defaults/plugins/app-defaults/src/index.ts @@ -13,4 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { appModuleDefaults as default } from './module'; +export * from './module'; + +export { appDefaults as default } from './module'; diff --git a/workspaces/app-defaults/plugins/app-defaults/src/module.tsx b/workspaces/app-defaults/plugins/app-defaults/src/module.tsx index 9c254d801b..f776d0058f 100644 --- a/workspaces/app-defaults/plugins/app-defaults/src/module.tsx +++ b/workspaces/app-defaults/plugins/app-defaults/src/module.tsx @@ -15,9 +15,11 @@ */ import { createFrontendModule } from '@backstage/frontend-plugin-api'; -export const appModuleDefaults = createFrontendModule({ +import { appDrawerExtensions } from './drawer'; + +export { appDrawerExtensions } from './drawer'; + +export const appDefaults = createFrontendModule({ pluginId: 'app', - extensions: [ - /* TODO */ - ], + extensions: [...appDrawerExtensions], }); diff --git a/workspaces/app-defaults/plugins/app-integrations/knip-report.md b/workspaces/app-defaults/plugins/app-integrations/knip-report.md new file mode 100644 index 0000000000..bebd1c7858 --- /dev/null +++ b/workspaces/app-defaults/plugins/app-integrations/knip-report.md @@ -0,0 +1,9 @@ +# Knip report + +## Unused devDependencies (2) + +| Name | Location | Severity | +| :--------------------- | :---------------- | :------- | +| @testing-library/react | package.json:60:6 | error | +| @backstage/test-utils | package.json:58:6 | error | + diff --git a/workspaces/app-defaults/plugins/app-react/README.md b/workspaces/app-defaults/plugins/app-react/README.md index 954193c266..a75b0aaadd 100644 --- a/workspaces/app-defaults/plugins/app-react/README.md +++ b/workspaces/app-defaults/plugins/app-react/README.md @@ -6,7 +6,7 @@ with host-owned state. ## Installation -Add the package as a dependency in your plugin or app: +Add the package as a dependency in your plugin: ```bash yarn add @red-hat-developer-hub/backstage-plugin-app-react @@ -14,36 +14,19 @@ yarn add @red-hat-developer-hub/backstage-plugin-app-react ## App Integration -Register the drawer module in your app's `createApp` call: - -```typescript -import { createApp } from '@backstage/frontend-defaults'; -import { appDrawerModule } from '@red-hat-developer-hub/backstage-plugin-app-react/alpha'; - -export default createApp({ - features: [ - appDrawerModule, - // ...other plugins and modules - ], -}); -``` - -This registers a single wrapper extension (`app-root-wrapper:app/drawer`) that -renders the `ApplicationDrawer` around the app content and accepts drawer -content contributions via inputs. Drawer state is managed by a global singleton -store, so `useAppDrawer()` works from anywhere in the React tree without a -wrapping provider. +To register the default RHDH modules, and to enable the drawers in your app, +you must install `@red-hat-developer-hub/backstage-plugin-app-defaults` +and register this in your `createApp` or use the Backstage feature auto discovery. ## Plugin Author Guide ### Contributing a Drawer -Use `AppDrawerContentBlueprint` to declare drawer content in your plugin's -`/alpha` export: +Use `AppDrawerContentBlueprint` to declare drawer content in your plugin: ```typescript import { createFrontendPlugin } from '@backstage/frontend-plugin-api'; -import { AppDrawerContentBlueprint } from '@red-hat-developer-hub/backstage-plugin-app-react/alpha'; +import { AppDrawerContentBlueprint } from '@red-hat-developer-hub/backstage-plugin-app-react'; const myDrawerExtension = AppDrawerContentBlueprint.make({ name: 'my-drawer', @@ -134,17 +117,10 @@ function MyDrawerContent() { } ``` -## Exports +### Exports -### Main entry (`@red-hat-developer-hub/backstage-plugin-app-react`) - -- `useAppDrawer` -- hook to control drawers -- `ApplicationDrawer` -- drawer renderer component -- `DrawerPanel` -- low-level MUI drawer wrapper -- `AppDrawerContent` / `AppDrawerApi` / `ApplicationDrawerProps` / `DrawerPanelProps` types - -### Alpha entry (`@red-hat-developer-hub/backstage-plugin-app-react/alpha`) +From `@red-hat-developer-hub/backstage-plugin-app-react`: - `appDrawerContentDataRef` -- extension data ref - `AppDrawerContentBlueprint` -- blueprint for contributing drawers -- `appDrawerModule` -- frontend module (registers the drawer wrapper extension) +- `useAppDrawer` -- hook to control drawers diff --git a/workspaces/app-defaults/plugins/app-react/knip-report.md b/workspaces/app-defaults/plugins/app-react/knip-report.md index c1d78fa7fe..f84b4731dd 100644 --- a/workspaces/app-defaults/plugins/app-react/knip-report.md +++ b/workspaces/app-defaults/plugins/app-react/knip-report.md @@ -1,14 +1,8 @@ # Knip report -## Unused dependencies (1) - -| Name | Location | Severity | -| :------------------------- | :---------------- | :------- | -| @backstage/core-plugin-api | package.json:49:6 | error | - ## Unused devDependencies (1) | Name | Location | Severity | | :-------------------- | :---------------- | :------- | -| @backstage/test-utils | package.json:59:6 | error | +| @backstage/test-utils | package.json:57:6 | error | diff --git a/workspaces/app-defaults/plugins/app-react/package.json b/workspaces/app-defaults/plugins/app-react/package.json index 11822fae3d..9c863bfd40 100644 --- a/workspaces/app-defaults/plugins/app-react/package.json +++ b/workspaces/app-defaults/plugins/app-react/package.json @@ -5,21 +5,6 @@ "description": "Shared UI components and extension APIs for the RHDH app shell", "main": "src/index.ts", "types": "src/index.ts", - "exports": { - ".": "./src/index.ts", - "./alpha": "./src/alpha.ts", - "./package.json": "./package.json" - }, - "typesVersions": { - "*": { - "alpha": [ - "src/alpha.ts" - ], - "package.json": [ - "package.json" - ] - } - }, "publishConfig": { "access": "public" }, @@ -46,11 +31,8 @@ "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/core-plugin-api": "^1.12.4", "@backstage/frontend-plugin-api": "^0.15.1", - "@backstage/plugin-app-react": "^0.2.1", - "@backstage/version-bridge": "^1.0.12", - "@mui/material": "5.18.0" + "@backstage/version-bridge": "^1.0.12" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0 || ^18.0.0" diff --git a/workspaces/app-defaults/plugins/app-react/report-alpha.api.md b/workspaces/app-defaults/plugins/app-react/report-alpha.api.md deleted file mode 100644 index 6e423b6010..0000000000 --- a/workspaces/app-defaults/plugins/app-react/report-alpha.api.md +++ /dev/null @@ -1,100 +0,0 @@ -## API Report File for "@red-hat-developer-hub/backstage-plugin-app-react" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; -import { ExtensionBlueprint } from '@backstage/frontend-plugin-api'; -import { ExtensionDataRef } from '@backstage/frontend-plugin-api'; -import { FrontendModule } from '@backstage/frontend-plugin-api'; -import { JSX as JSX_2 } from 'react/jsx-runtime'; - -// @public -export interface AppDrawerApi { - activeDrawerId: string | null; - closeDrawer(id: string): void; - getWidth(id: string): number; - isOpen(id: string): boolean; - openDrawer(id: string): void; - setWidth(id: string, width: number): void; - toggleDrawer(id: string): void; -} - -// @public -export interface AppDrawerContent { - defaultWidth?: number; - element: React.ReactElement; - id: string; - priority?: number; - resizable?: boolean; -} - -// @alpha -export const AppDrawerContentBlueprint: ExtensionBlueprint<{ - kind: 'app-drawer-content'; - params: { - id: string; - element: React.ReactElement; - resizable?: boolean; - defaultWidth?: number; - priority?: number; - }; - output: ExtensionDataRef; - inputs: {}; - config: { - defaultWidth: number | undefined; - resizable: boolean | undefined; - priority: number | undefined; - }; - configInput: { - defaultWidth?: number | undefined; - resizable?: boolean | undefined; - priority?: number | undefined; - }; - dataRefs: { - content: ConfigurableExtensionDataRef< - AppDrawerContent, - 'app.drawer.content', - {} - >; - }; -}>; - -// @alpha -export const appDrawerContentDataRef: ConfigurableExtensionDataRef< - AppDrawerContent, - 'app.drawer.content', - {} ->; - -// @alpha -export const appDrawerModule: FrontendModule; - -// @public -export const ApplicationDrawer: ( - input: ApplicationDrawerProps, -) => JSX_2.Element; - -// @public -export interface ApplicationDrawerProps { - children: React.ReactNode; - contents: AppDrawerContent[]; -} - -// @public -export const DrawerPanel: (props: DrawerPanelProps) => JSX_2.Element; - -// @public -export interface DrawerPanelProps { - children: React.ReactNode; - drawerWidth?: number; - isDrawerOpen: boolean; - isResizable?: boolean; - maxWidth?: number; - minWidth?: number; - onWidthChange?: (width: number) => void; -} - -// @public -export const useAppDrawer: () => AppDrawerApi; -``` diff --git a/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/AppDrawerContentBlueprint.ts b/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/AppDrawerContentBlueprint.ts index f89edfe8be..a9e23c1a2e 100644 --- a/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/AppDrawerContentBlueprint.ts +++ b/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/AppDrawerContentBlueprint.ts @@ -46,7 +46,7 @@ import { appDrawerContentDataRef } from './appDrawerContentDataRef'; * }); * ``` * - * @alpha + * @public */ export const AppDrawerContentBlueprint = createExtensionBlueprint({ kind: 'app-drawer-content', diff --git a/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/appDrawerContentDataRef.ts b/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/appDrawerContentDataRef.ts index 0e60978528..57e087378b 100644 --- a/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/appDrawerContentDataRef.ts +++ b/workspaces/app-defaults/plugins/app-react/src/drawer/extensions/appDrawerContentDataRef.ts @@ -21,7 +21,7 @@ import type { AppDrawerContent } from '../types'; /** * Extension data ref carrying drawer content from a plugin to the host. * - * @alpha + * @public */ export const appDrawerContentDataRef = createExtensionDataRef().with({ diff --git a/workspaces/app-defaults/plugins/app-react/src/drawer/index.ts b/workspaces/app-defaults/plugins/app-react/src/drawer/index.ts index 8d8203c9e6..b2bdaa58ac 100644 --- a/workspaces/app-defaults/plugins/app-react/src/drawer/index.ts +++ b/workspaces/app-defaults/plugins/app-react/src/drawer/index.ts @@ -14,14 +14,10 @@ * limitations under the License. */ -export { useAppDrawer } from './hooks/useAppDrawer'; -export { ApplicationDrawer } from './components/ApplicationDrawer'; -export { DrawerPanel } from './components/DrawerPanel'; - export { appDrawerContentDataRef } from './extensions/appDrawerContentDataRef'; export { AppDrawerContentBlueprint } from './extensions/AppDrawerContentBlueprint'; -export { appDrawerModule } from './extensions/appDrawerModule'; -export type { ApplicationDrawerProps } from './components/ApplicationDrawer'; -export type { DrawerPanelProps } from './components/DrawerPanel'; +export { useAppDrawer } from './hooks/useAppDrawer'; +export { drawerStore } from './utils/drawerStore'; + export type { AppDrawerContent, AppDrawerApi } from './types'; diff --git a/workspaces/app-defaults/plugins/app-react/src/index.ts b/workspaces/app-defaults/plugins/app-react/src/index.ts index aeab03915d..b7778f8d0e 100644 --- a/workspaces/app-defaults/plugins/app-react/src/index.ts +++ b/workspaces/app-defaults/plugins/app-react/src/index.ts @@ -20,9 +20,4 @@ * @packageDocumentation */ -export { useAppDrawer } from './drawer'; -export { ApplicationDrawer } from './drawer'; -export { DrawerPanel } from './drawer'; -export type { ApplicationDrawerProps } from './drawer'; -export type { DrawerPanelProps } from './drawer'; -export type { AppDrawerContent, AppDrawerApi } from './drawer'; +export * from './drawer'; diff --git a/workspaces/app-defaults/yarn.lock b/workspaces/app-defaults/yarn.lock index 926af1320d..32412730e5 100644 --- a/workspaces/app-defaults/yarn.lock +++ b/workspaces/app-defaults/yarn.lock @@ -11230,6 +11230,22 @@ __metadata: languageName: unknown linkType: soft +"@red-hat-developer-hub/backstage-plugin-app-defaults@workspace:^, @red-hat-developer-hub/backstage-plugin-app-defaults@workspace:plugins/app-defaults": + version: 0.0.0-use.local + resolution: "@red-hat-developer-hub/backstage-plugin-app-defaults@workspace:plugins/app-defaults" + dependencies: + "@backstage/cli": "npm:^0.36.0" + "@backstage/frontend-plugin-api": "npm:^0.15.0" + "@backstage/plugin-app-react": "npm:^0.2.1" + "@mui/material": "npm:5.18.0" + "@red-hat-developer-hub/backstage-plugin-app-react": "workspace:^" + "@testing-library/jest-dom": "npm:^6.0.0" + "@testing-library/react": "npm:^16.0.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + languageName: unknown + linkType: soft + "@red-hat-developer-hub/backstage-plugin-app-integrations@workspace:^, @red-hat-developer-hub/backstage-plugin-app-integrations@workspace:plugins/app-integrations": version: 0.0.0-use.local resolution: "@red-hat-developer-hub/backstage-plugin-app-integrations@workspace:plugins/app-integrations" @@ -11252,27 +11268,14 @@ __metadata: languageName: unknown linkType: soft -"@red-hat-developer-hub/backstage-plugin-app-defaults@workspace:^, @red-hat-developer-hub/backstage-plugin-app-defaults@workspace:plugins/app-module-defaults": - version: 0.0.0-use.local - resolution: "@red-hat-developer-hub/backstage-plugin-app-defaults@workspace:plugins/app-module-defaults" - dependencies: - "@backstage/cli": "npm:^0.36.0" - "@backstage/frontend-plugin-api": "npm:^0.15.0" - "@testing-library/jest-dom": "npm:^6.0.0" - languageName: unknown - linkType: soft - "@red-hat-developer-hub/backstage-plugin-app-react@workspace:^, @red-hat-developer-hub/backstage-plugin-app-react@workspace:plugins/app-react": version: 0.0.0-use.local resolution: "@red-hat-developer-hub/backstage-plugin-app-react@workspace:plugins/app-react" dependencies: "@backstage/cli": "npm:^0.36.0" - "@backstage/core-plugin-api": "npm:^1.12.4" "@backstage/frontend-plugin-api": "npm:^0.15.1" - "@backstage/plugin-app-react": "npm:^0.2.1" "@backstage/test-utils": "npm:^1.7.16" "@backstage/version-bridge": "npm:^1.0.12" - "@mui/material": "npm:5.18.0" "@testing-library/jest-dom": "npm:^6.0.0" "@testing-library/react": "npm:^16.0.0" cross-fetch: "npm:^4.0.0" @@ -15983,8 +15986,8 @@ __metadata: "@mui/material": "npm:^5.18.0" "@playwright/test": "npm:^1.58.2" "@red-hat-developer-hub/backstage-plugin-app-auth": "workspace:^" - "@red-hat-developer-hub/backstage-plugin-app-integrations": "workspace:^" "@red-hat-developer-hub/backstage-plugin-app-defaults": "workspace:^" + "@red-hat-developer-hub/backstage-plugin-app-integrations": "workspace:^" "@red-hat-developer-hub/backstage-plugin-app-react": "workspace:^" "@red-hat-developer-hub/backstage-plugin-global-header": "npm:^1.21.0" "@testing-library/dom": "npm:^10.0.0" From 7658e52810b6a61c99140fbe000b1f18e831e4d1 Mon Sep 17 00:00:00 2001 From: its-mitesh-kumar Date: Sat, 20 Jun 2026 21:39:31 +0530 Subject: [PATCH 3/3] feat(lightspeed): expose dedicated NFS module federation entry points for FAB and translations - Add lightspeedFABModuleExport.ts and lightspeedTranslationsModuleExport.ts as dedicated default-export entry points required by dynamicFrontendFeaturesLoader - Update package.json exports, typesVersions, and scalprum.exposedModules to register both modules as separate Module Federation containers - Fix React Context duplication across MF boundaries using globalThis singleton pattern in LightspeedDrawerContext, resolving "useLightspeedDrawerContext must be used within a LightspeedDrawerProvider" error in Dock-to-Window mode Signed-off-by: its-mitesh-kumar Co-authored-by: Cursor --- .../lightspeed/.changeset/bright-waves-flow.md | 5 +++++ .../lightspeed/plugins/lightspeed/package.json | 10 ++++++++++ .../report-lightspeed-fab-module.api.md | 13 +++++++++++++ ...report-lightspeed-translations-module.api.md | 13 +++++++++++++ .../src/alpha/lightspeedFABModuleExport.ts | 16 ++++++++++++++++ .../alpha/lightspeedTranslationsModuleExport.ts | 16 ++++++++++++++++ .../src/components/LightspeedDrawerContext.tsx | 17 +++++++++++++---- 7 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 workspaces/lightspeed/.changeset/bright-waves-flow.md create mode 100644 workspaces/lightspeed/plugins/lightspeed/report-lightspeed-fab-module.api.md create mode 100644 workspaces/lightspeed/plugins/lightspeed/report-lightspeed-translations-module.api.md create mode 100644 workspaces/lightspeed/plugins/lightspeed/src/alpha/lightspeedFABModuleExport.ts create mode 100644 workspaces/lightspeed/plugins/lightspeed/src/alpha/lightspeedTranslationsModuleExport.ts diff --git a/workspaces/lightspeed/.changeset/bright-waves-flow.md b/workspaces/lightspeed/.changeset/bright-waves-flow.md new file mode 100644 index 0000000000..3668e9d2b5 --- /dev/null +++ b/workspaces/lightspeed/.changeset/bright-waves-flow.md @@ -0,0 +1,5 @@ +--- +'@red-hat-developer-hub/backstage-plugin-lightspeed': minor +--- + +Expose dedicated Module Federation entry points for FAB and translations modules, and fix React Context duplication across MF boundaries using a globalThis singleton pattern. diff --git a/workspaces/lightspeed/plugins/lightspeed/package.json b/workspaces/lightspeed/plugins/lightspeed/package.json index aee0807718..6ee6730e73 100644 --- a/workspaces/lightspeed/plugins/lightspeed/package.json +++ b/workspaces/lightspeed/plugins/lightspeed/package.json @@ -10,6 +10,8 @@ "exports": { ".": "./src/index.ts", "./alpha": "./src/alpha/index.tsx", + "./lightspeed-fab-module": "./src/alpha/lightspeedFABModuleExport.ts", + "./lightspeed-translations-module": "./src/alpha/lightspeedTranslationsModuleExport.ts", "./dev": "./dev/CustomDrawer.tsx", "./package.json": "./package.json" }, @@ -18,6 +20,12 @@ "alpha": [ "src/alpha/index.tsx" ], + "lightspeed-fab-module": [ + "src/alpha/lightspeedFABModuleExport.ts" + ], + "lightspeed-translations-module": [ + "src/alpha/lightspeedTranslationsModuleExport.ts" + ], "dev": [ "dev/CustomDrawer.tsx" ], @@ -110,6 +118,8 @@ "name": "red-hat-developer-hub.backstage-plugin-lightspeed", "exposedModules": { "Alpha": "./src/alpha/index.tsx", + "LightspeedFABModule": "./src/alpha/lightspeedFABModuleExport.ts", + "LightspeedTranslationsModule": "./src/alpha/lightspeedTranslationsModuleExport.ts", "PluginRoot": "./src/index.ts", "LightspeedPlugin": "./src/index.ts" } diff --git a/workspaces/lightspeed/plugins/lightspeed/report-lightspeed-fab-module.api.md b/workspaces/lightspeed/plugins/lightspeed/report-lightspeed-fab-module.api.md new file mode 100644 index 0000000000..e25697607d --- /dev/null +++ b/workspaces/lightspeed/plugins/lightspeed/report-lightspeed-fab-module.api.md @@ -0,0 +1,13 @@ +## API Report File for "@red-hat-developer-hub/backstage-plugin-lightspeed" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { FrontendModule } from '@backstage/frontend-plugin-api'; + +// @alpha (undocumented) +const lightspeedFABModule: FrontendModule; +export default lightspeedFABModule; + +// (No @packageDocumentation comment for this package) +``` diff --git a/workspaces/lightspeed/plugins/lightspeed/report-lightspeed-translations-module.api.md b/workspaces/lightspeed/plugins/lightspeed/report-lightspeed-translations-module.api.md new file mode 100644 index 0000000000..af32daaef6 --- /dev/null +++ b/workspaces/lightspeed/plugins/lightspeed/report-lightspeed-translations-module.api.md @@ -0,0 +1,13 @@ +## API Report File for "@red-hat-developer-hub/backstage-plugin-lightspeed" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { FrontendModule } from '@backstage/frontend-plugin-api'; + +// @alpha +const lightspeedTranslationsModule: FrontendModule; +export default lightspeedTranslationsModule; + +// (No @packageDocumentation comment for this package) +``` diff --git a/workspaces/lightspeed/plugins/lightspeed/src/alpha/lightspeedFABModuleExport.ts b/workspaces/lightspeed/plugins/lightspeed/src/alpha/lightspeedFABModuleExport.ts new file mode 100644 index 0000000000..38a02fbe80 --- /dev/null +++ b/workspaces/lightspeed/plugins/lightspeed/src/alpha/lightspeedFABModuleExport.ts @@ -0,0 +1,16 @@ +/* + * Copyright Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { lightspeedFABModule as default } from './index'; diff --git a/workspaces/lightspeed/plugins/lightspeed/src/alpha/lightspeedTranslationsModuleExport.ts b/workspaces/lightspeed/plugins/lightspeed/src/alpha/lightspeedTranslationsModuleExport.ts new file mode 100644 index 0000000000..30b08b07e7 --- /dev/null +++ b/workspaces/lightspeed/plugins/lightspeed/src/alpha/lightspeedTranslationsModuleExport.ts @@ -0,0 +1,16 @@ +/* + * Copyright Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { lightspeedTranslationsModule as default } from './index'; diff --git a/workspaces/lightspeed/plugins/lightspeed/src/components/LightspeedDrawerContext.tsx b/workspaces/lightspeed/plugins/lightspeed/src/components/LightspeedDrawerContext.tsx index 27bbd18e90..6269c9ff7f 100644 --- a/workspaces/lightspeed/plugins/lightspeed/src/components/LightspeedDrawerContext.tsx +++ b/workspaces/lightspeed/plugins/lightspeed/src/components/LightspeedDrawerContext.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createContext } from 'react'; +import React, { createContext } from 'react'; import { ChatbotDisplayMode } from '@patternfly/chatbot'; @@ -108,9 +108,18 @@ export interface LightspeedDrawerContextType { setShellViewTab: (tab: number) => void; } +const CONTEXT_KEY = '__lightspeed_drawer_context__' as keyof typeof globalThis; + +function getOrCreateContext() { + const existing = (globalThis as any)[CONTEXT_KEY]; + if (existing) + return existing as React.Context; + const ctx = createContext(undefined); + (globalThis as any)[CONTEXT_KEY] = ctx; + return ctx; +} + /** * @public */ -export const LightspeedDrawerContext = createContext< - LightspeedDrawerContextType | undefined ->(undefined); +export const LightspeedDrawerContext = getOrCreateContext();