feat(app): migrate portal to Backstage New Frontend System#621
feat(app): migrate portal to Backstage New Frontend System#621kaviththiranga wants to merge 44 commits into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR migrates the OpenChoreo Backstage plugin suite and host app to Backstage's New Frontend System by adding ChangesBackstage NFS Migration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/app/src/apis/customOverrides.tsx`:
- Around line 132-150: The kindIcons map in customOverrides.tsx is missing an
entry for "clusterworkflow", causing App.tsx's kind:clusterworkflow to fall back
to the default icon; add a "clusterworkflow" key to the kindIcons object (same
icon as "workflow", i.e., PlayCircleOutlineIcon) so cluster workflow entities
render with the expected legacy icon; update the kindIcons object where other
mappings (environment, workflow, clusterworkflowplane, etc.) are defined.
In `@plugins/openchoreo/src/alpha.tsx`:
- Around line 39-41: The pluginId passed to createFrontendPlugin in
plugins/openchoreo/src/alpha.tsx is 'openchoreo' but must match the package.json
backstage.pluginId ('plugin-openchoreo'); update the pluginId in the
createFrontendPlugin call to exactly match the package metadata (use the
'plugin-openchoreo' string) so the plugin metadata/wiring works correctly, and
apply the same fix pattern for the other affected plugin (update
createFrontendPlugin's pluginId in the platform-engineer-core frontend entry to
match its package.json backstage.pluginId 'plugin-platform-engineer-core').
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a239483f-be48-4cfc-86ba-4c4a1bb8550a
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (19)
.changeset/migrate-portal-to-nfs.mdpackages/app/package.jsonpackages/app/src/App.test.tsxpackages/app/src/App.tsxpackages/app/src/apis.tspackages/app/src/apis/customOverrides.tsxpackages/app/src/components/DynamicSignInPage.tsxpackages/app/src/components/Root/Root.tsxpackages/app/src/index.tsxplugins/openchoreo-ci/package.jsonplugins/openchoreo-ci/src/alpha.tsxplugins/openchoreo-observability/package.jsonplugins/openchoreo-observability/src/alpha.tsxplugins/openchoreo-workflows/package.jsonplugins/openchoreo-workflows/src/alpha.tsxplugins/openchoreo/package.jsonplugins/openchoreo/src/alpha.tsxplugins/platform-engineer-core/package.jsonplugins/platform-engineer-core/src/alpha.tsx
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Pulls @backstage/frontend-defaults, frontend-app-api, frontend-plugin-api, core-compat-api, plugin-app, plugin-app-react forward to their ^0.17.0-line versions so createFrontendPlugin/blueprint imports type-check against a single resolved frontend-plugin-api. Required preparation before NFS plugin conversion. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Expose the plugin via @backstage/frontend-plugin-api's createFrontendPlugin in src/alpha.tsx so the NFS app shell can consume it directly. The legacy src/plugin.ts and dev sandbox continue to work unchanged. Mirrors the upstream pattern used by @backstage/plugin-api-docs and friends. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Expose the plugin as a createFrontendPlugin with the GenericWorkflowsClient API and the GenericWorkflowsPage routable extension translated to a PageBlueprint. Legacy src/plugin.ts remains unchanged. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Expose the plugin as a createFrontendPlugin with the PlatformEngineerDashboardView translated to a PageBlueprint. Legacy src/plugin.ts and dev sandbox unchanged. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Register the three observability backend APIs (observability, RCA agent, FinOps agent) as ApiBlueprint extensions. The nine legacy routable extensions (Metrics, Traces, RCA, Logs, Alerts, Wirelogs, Incidents, CostAnalysis) keep flowing through src/plugin.ts because the host app mounts them with per- mount props inside legacy EntityLayout.Route blocks. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Register the OpenChoreoClient API as an ApiBlueprint extension and expose the plugin's three route refs (catalogEnvironment, accessControl, resourceEnvironments). The four legacy routable extensions and four component cards continue to flow through src/plugin.ts; the host app mounts them as plain React components inside EntityLayout. Step 2 is now complete for all five custom plugins. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…aults Step 3a of the NFS migration: - App.tsx swaps `createApp` from `@backstage/app-defaults` for the NFS one from `@backstage/frontend-defaults`. Existing apis/icons/components.SignInPage/ themes flow through `convertLegacyAppOptions`; the entire FlatRoutes JSX tree including AppRouter and Root flows through `convertLegacyAppRoot`. - index.tsx and App.test.tsx switch from `<App />` to rendering the JSX value `app` directly, matching the upstream NFS reference app. - Two `app`-scoped API factories (`catalogGraphApiRef`, `entityPresentationApiRef`) are temporarily disabled — under NFS they collide with the upstream plugins that already own those API ids. The proper plugin-scoped overrides land in Step 3c. - `__experimentalTranslations` (catalog-import strings) is deferred to 3c as a TranslationBlueprint module. Dev server boots clean, sign-in + home page verified live. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Step 3b of the NFS migration: - Wire the five custom plugins from Step 2 (openchoreo, openchoreo-ci, openchoreo-observability, openchoreo-workflows, platform-engineer-core) as NFS features via their `/alpha` default exports. - Drop the now-duplicate `openChoreoCiClientApiRef` and `genericWorkflowsClientApiRef` factory registrations from `apis.ts`; the plugins own them now. - Register `@backstage/plugin-scaffolder/alpha` so the legacy scaffolder route refs (used by `useRouteRef(scaffolderPlugin.routes.root)` inside `useKindCreateConfig`) resolve under NFS. Without it the catalog page crashes inside `ContextAwareCreateButton`. - Defer the scaffolder form-decorators override (custom `openChoreoTokenDecorator`) to Step 3c; under NFS the app-scoped factory collides with the scaffolder plugin's own default. Known regressions to fix in Step 3c: - `/create` shows upstream's NFS scaffolder Templates page, not our `CustomTemplateListPage`/`CustomReviewStep`/`ScaffolderLayout` or the 27 field extensions. They'll move to a scaffolder override + field- extension modules. - Catalog graph relations and entity-presentation kind icons remain on upstream defaults. Verified live: sign-in, home, catalog index, system entity page (all 9 observability tabs visible) render cleanly. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Part of Step 3c (scaffolder customizations). Disable the upstream NFS \`page:scaffolder\` extension via \`scaffolderPlugin.withOverrides\` so the legacy \`<ScaffolderPage>\` mount in \`<FlatRoutes>\` (preserved via \`convertLegacyAppRoot\`) owns the page again. The plugin's route refs and other extensions stay active so \`useRouteRef(scaffolderPlugin.routes.root)\` still resolves. \`convertLegacyAppRoot\` requires the route element to BE the routable extension; it cannot see through wrapper components. So: - Remove \`<ScaffolderLayout>\` and \`<ScaffolderPreselectionProvider>\` from the \`/create\` route element. \`<ScaffolderPage>\` is now the direct element. - Hoist \`<ScaffolderPreselectionProvider>\` to wrap \`<Root>\` so the URL preselection still propagates to ProjectNamespaceField and NamespaceEntityPicker. The provider only reads \`useSearchParams\`, so wrapping the whole app is safe. - \`ScaffolderLayout\` (a CSS-only width constraint for scaffolder cards) is dropped for now; the cards will be unconstrained until a future CSS-scoped replacement lands in \`buiOverrides.css\`. Verified live: /create renders our \`CustomTemplateListPage\` (not upstream's Templates UI), template wizard shows custom field extensions and \`CustomReviewStep\`, catalog/home unchanged. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…errides
Part of Step 3c (continued).
Move the three upstream API factories that we customize under their owning
plugin's pluginId, replacing the `app`-scoped registrations that previously
caused API_FACTORY_CONFLICT under NFS:
- catalog-graph: \`api:catalog-graph\` override carries the OpenChoreo custom
relations (deploysTo, hostedOn, instanceOf, …) and relation pairs.
- catalog: \`api:catalog/entity-presentation\` override carries the kind
icons for Environment, DataPlane, DeploymentPipeline, etc.
- scaffolder: \`api:scaffolder/form-decorators\` override re-injects the
\`openChoreoTokenDecorator\` for user-based authorization on scaffolder
actions. The \`page:scaffolder\` extension disable from the previous
commit moves into the same overrides module.
The override pattern uses \`pluginAlpha.getExtension(id).override({ params:
defineParams => defineParams({...}) })\` since ApiBlueprint takes its
params as a callback in the v0.17 frontend-plugin-api.
All three overrides live in a new \`packages/app/src/apis/customOverrides.tsx\`
to keep App.tsx tidy.
Verified live: catalog index, catalog graph, system entity Relations card,
scaffolder template wizard all render with our customizations active and
no startup conflicts.
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…lugin
Final piece of Step 3c.
Add a TranslationBlueprint module that reinstates the catalog-import header
overrides (`Register an existing catalog entity` etc.) that previously rode
via createApp.__experimentalTranslations.
Register \`@backstage/plugin-catalog-import/alpha\` so the
\`routeRef{id=catalog-import}\` resolves under NFS; without it the legacy
\`<RequirePermission><CatalogImportPage /></...>\` mount inside <FlatRoutes>
fails at runtime with "Routable extension component … was not discovered".
Verified live: /catalog-import shows the customized title and supporting
text, no errors.
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Step 3d.
Move \`DynamicSignInPage\` (the OIDC vs guest auth switcher) out of App.tsx
into its own \`packages/app/src/components/DynamicSignInPage.tsx\` and
register it through \`SignInPageBlueprint.make({ loader: () => import(...) })\`
inside the renamed \`customAppModule\` (was \`customTranslationsModule\`,
now holds both the sign-in extension and the translation overrides since
both target \`pluginId: 'app'\`).
Drop \`components.SignInPage: DynamicSignInPage\` from
\`convertLegacyAppOptions\` and the now-unused
\`SignInPage\`/\`configApiRef\`/\`useApi\`/\`openChoreoAuthApiRef\` imports from
App.tsx.
Verified live: signed out, the OpenChoreo \"Sign in using OpenChoreo\"
button appears via the NFS blueprint, OIDC redirect to Thunder works,
sign-in completes, home page renders.
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Patch bump for the five custom plugins that gained `/alpha` NFS entry
points (openchoreo, openchoreo-ci, openchoreo-observability,
openchoreo-workflows, platform-engineer-core). Default export remains the
legacy `createPlugin` instance; new entry exposes the same plugin as a
`createFrontendPlugin` for use with `createApp({ features })`.
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…ries The CI/workflows clients and catalog-graph factory moved out of app-scope apis.ts into plugin /alpha modules and customOverrides.tsx during the NFS migration; this test was still asserting them in the app-scoped apis array. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…injection Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…rints Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
… blueprints Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…blueprint Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
08f4fab to
d4dd00f
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/app/src/apis/customOverrides.tsx`:
- Around line 149-153: The comment block starting at line 149 states that the
page:scaffolder extension is disabled, but this is inaccurate since the code at
line 272 actively overrides its loader. Update the comment to correctly reflect
that page:scaffolder is being overridden (not disabled) to inject the OpenChoreo
token for user-based authorization in scaffolder actions. Remove the misleading
statement about the legacy ScaffolderPage mount winning.
In `@packages/app/src/App.tsx`:
- Around line 140-153: The `/create` route in App.tsx currently uses
ScaffolderPage with minimal configuration while customOverrides.tsx
simultaneously registers an NFS override for page:scaffolder that loads
OpenChoreoScaffolderPage with full ScaffolderLayout and all 27 field extensions,
causing maintenance drift. Choose one approach: either remove or comment out the
NFS override registration for page:scaffolder in customOverrides.tsx to
eliminate the competing implementation, or replace the ScaffolderPage component
in the `/create` route definition with OpenChoreoScaffolderPage to consolidate
on the richer implementation. Apply the chosen fix consistently so there is a
single, clear source of truth for the create resource page.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: eef6f09d-a353-44fe-b71f-b4f936806300
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (35)
.changeset/fix-nfs-migration-followups.md.changeset/migrate-portal-to-nfs.mdpackages/app/package.jsonpackages/app/src/App.test.tsxpackages/app/src/App.tsxpackages/app/src/apis.test.tspackages/app/src/apis.tspackages/app/src/apis/customOverrides.tsxpackages/app/src/components/DynamicSignInPage.tsxpackages/app/src/components/Root/Root.tsxpackages/app/src/components/catalog/EntityPage.tsxpackages/app/src/components/scaffolder/OpenChoreoScaffolderPage.tsxpackages/app/src/components/settings/OpenChoreoProviderSettings.tsxpackages/app/src/index.tsxpackages/app/src/kindIcons.tspackages/app/src/scaffolder/ScaffolderPreselectionContext.tsxplugins/openchoreo-ci/package.jsonplugins/openchoreo-ci/src/alpha.tsxplugins/openchoreo-observability/package.jsonplugins/openchoreo-observability/src/alpha.tsxplugins/openchoreo-observability/src/alpha/LogRowActionBlueprint.tsplugins/openchoreo-observability/src/api/LogRowActionRendererApi.tsplugins/openchoreo-observability/src/api/index.tsplugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.tsxplugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityRuntimeLogsPage.tsxplugins/openchoreo-observability/src/index.tsplugins/openchoreo-react/src/components/FeatureGate/FeatureGatedContent.tsxplugins/openchoreo-react/src/components/FeatureGate/index.tsplugins/openchoreo-react/src/index.tsplugins/openchoreo-workflows/package.jsonplugins/openchoreo-workflows/src/alpha.tsxplugins/openchoreo/package.jsonplugins/openchoreo/src/alpha.tsxplugins/platform-engineer-core/package.jsonplugins/platform-engineer-core/src/alpha.tsx
💤 Files with no reviewable changes (1)
- packages/app/src/apis.ts
✅ Files skipped from review due to trivial changes (5)
- packages/app/src/components/settings/OpenChoreoProviderSettings.tsx
- plugins/openchoreo-observability/src/index.ts
- packages/app/src/App.test.tsx
- plugins/openchoreo-react/src/components/FeatureGate/index.ts
- .changeset/migrate-portal-to-nfs.md
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/app/src/index.tsx
- plugins/openchoreo-observability/package.json
- plugins/openchoreo-ci/src/alpha.tsx
- packages/app/package.json
- packages/app/src/apis.test.ts
- plugins/openchoreo-workflows/package.json
- plugins/platform-engineer-core/src/alpha.tsx
- plugins/openchoreo/package.json
…y override" This reverts commit bf2ac84. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
… api re-emission Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…ock scaffolder.root binding Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…derPage Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…caffolderLayout Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…utes Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
…ha extensions Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
d4dd00f to
933b02f
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/app/src/apis/customOverrides.test.tsx (1)
33-46: ⚡ Quick winConsider verifying specific extension names instead of just the count.
The test extracts extension
idson line 40 but only checks that exactly 5 exist. This is brittle—adding or removing an extension requires updating the hardcoded5. Consider asserting the presence of the specific named extensions documented in the comment (e.g.,'catalog-import-overrides','investigate-log','openchoreo-about','workflows-or-external-ci') to make the test more robust and self-documenting.♻️ Suggested enhancement
const ids = extensions.map(e => e.id); // The host registers exactly five extensions on the app module today: // a SignInPage, a Translation override (catalog-import), a // LogRowAction renderer, the OpenChoreoAboutCard, and the // WorkflowsOrExternalCICard. - expect(ids).toHaveLength(5); + expect(ids).toHaveLength(5); + // Verify the known named extensions are present + expect(ids).toContain('catalog-import-overrides'); + expect(ids).toContain('investigate-log'); + expect(ids).toContain('openchoreo-about'); + expect(ids).toContain('workflows-or-external-ci');🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/app/src/apis/customOverrides.test.tsx` around lines 33 - 46, The test in the 'registers extensions on the customAppModule' test case extracts extension ids but only verifies the hardcoded count of 5 using expect(ids).toHaveLength(5), which is brittle and requires manual updates when extensions change. Replace the length assertion with specific checks for the named extensions documented in the comment (such as 'catalog-import-overrides', 'investigate-log', 'openchoreo-about', and 'workflows-or-external-ci') by using expect(ids).toContain() or similar matchers to verify that each expected extension id is present in the ids array. This makes the test more resilient to changes and self-documenting.plugins/openchoreo/src/alpha.test.tsx (1)
61-77: 💤 Low valueConsider adding a type guard for improved type safety.
The tests use
as anyto access the internal plugin structure, which bypasses type checking. While this is acceptable and common for testing framework internals, you could improve type safety with a minimal interface:interface PluginWithInternals { id: string; extensions: Array<{ id: string }>; }Then cast to this interface instead of
any. This preserves the intent while catching potential structural changes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugins/openchoreo/src/alpha.test.tsx` around lines 61 - 77, The test blocks use `as any` casts when accessing the plugin's extensions property, which bypasses type checking. Define a type guard interface (e.g., PluginWithInternals) that specifies the shape of the plugin with an extensions property, then replace both `as any` casts with casts to this new interface instead. This applies to both the first test checking for documented blueprint extensions and the second test checking the extension count. The interface should include the id property and the extensions array structure to maintain type safety while still allowing internal plugin structure access in tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.changeset/fix-nfs-migration-followups.md:
- Around line 23-25: The changelog entry in the
`.changeset/fix-nfs-migration-followups.md` file incorrectly lists ten
observability tabs but the PR objectives only include seven shipped features:
runtime logs, events, metrics, alerts, traces, incidents, and analysis. Remove
the references to Wirelogs, RCA Reports, and Cost Analysis from the changelog
entry, updating the count from ten to seven to accurately reflect what is
actually being shipped in this change. Keep the reference to the registry API
for host-injected log-row action renderers as that remains part of the
contribution.
---
Nitpick comments:
In `@packages/app/src/apis/customOverrides.test.tsx`:
- Around line 33-46: The test in the 'registers extensions on the
customAppModule' test case extracts extension ids but only verifies the
hardcoded count of 5 using expect(ids).toHaveLength(5), which is brittle and
requires manual updates when extensions change. Replace the length assertion
with specific checks for the named extensions documented in the comment (such as
'catalog-import-overrides', 'investigate-log', 'openchoreo-about', and
'workflows-or-external-ci') by using expect(ids).toContain() or similar matchers
to verify that each expected extension id is present in the ids array. This
makes the test more resilient to changes and self-documenting.
In `@plugins/openchoreo/src/alpha.test.tsx`:
- Around line 61-77: The test blocks use `as any` casts when accessing the
plugin's extensions property, which bypasses type checking. Define a type guard
interface (e.g., PluginWithInternals) that specifies the shape of the plugin
with an extensions property, then replace both `as any` casts with casts to this
new interface instead. This applies to both the first test checking for
documented blueprint extensions and the second test checking the extension
count. The interface should include the id property and the extensions array
structure to maintain type safety while still allowing internal plugin structure
access in tests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 93b3f3dd-bf03-4f02-868e-d1a385ab01b8
📒 Files selected for processing (18)
.changeset/fix-nfs-migration-followups.mdpackages/app/src/App.tsxpackages/app/src/apis.test.tspackages/app/src/apis.tspackages/app/src/apis/customOverrides.test.tsxpackages/app/src/apis/customOverrides.tsxpackages/app/src/components/DynamicSignInPage.tsxpackages/app/src/components/Root/Root.tsxpackages/app/src/components/scaffolder/OpenChoreoScaffolderPage.tsxpackages/app/src/components/settings/OpenChoreoProviderSettings.tsxpackages/app/src/kindIcons.tspackages/app/src/scaffolder/ScaffolderPreselectionContext.tsxplugins/openchoreo-observability/src/alpha.test.tsxplugins/openchoreo-observability/src/api/LogRowActionRendererApi.test.tsplugins/openchoreo-observability/src/api/LogRowActionRendererApi.tsplugins/openchoreo-workflows/src/alpha.test.tsxplugins/openchoreo/src/alpha.test.tsxplugins/openchoreo/src/alpha.tsx
💤 Files with no reviewable changes (1)
- packages/app/src/apis.ts
✅ Files skipped from review due to trivial changes (5)
- plugins/openchoreo-observability/src/alpha.test.tsx
- plugins/openchoreo-observability/src/api/LogRowActionRendererApi.test.ts
- packages/app/src/components/settings/OpenChoreoProviderSettings.tsx
- packages/app/src/kindIcons.ts
- packages/app/src/components/DynamicSignInPage.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
- packages/app/src/scaffolder/ScaffolderPreselectionContext.tsx
- packages/app/src/components/Root/Root.tsx
- packages/app/src/components/scaffolder/OpenChoreoScaffolderPage.tsx
- plugins/openchoreo/src/alpha.tsx
- packages/app/src/apis/customOverrides.tsx
- plugins/openchoreo-observability/src/api/LogRowActionRendererApi.ts
- packages/app/src/App.tsx
The createApp feature reorder let the NFS page:catalog/entity extension shadow the legacy CatalogEntityPage mount, dropping the custom CompactEntityHeader, hand-authored Overview JSX, and OpenChoreoEntityLayout tab styles. Override the NFS loader to render entityPage inside OpenChoreoCatalogEntityPage and remove the now-unused legacy route mount and host-side overview EntityCardBlueprints. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Gate EntityLayoutWithDelete on useAsyncEntity, remove the double wrap in OpenChoreoCatalogEntityPage (per-kind pages already provide it), and swap observability entity-tab exports to React.lazy — the unbound rootRouteRef crashed every observability tab. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Without their /alpha features in createApp, apiDocsConfigRef, kubernetesApiRef, and the related kubernetes apis are missing from the api holder. The Definition tab on kind:api entities and the Kubernetes tab on annotated components throw NotImplementedError at render time. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
Both pages rendered the small "Catalog" / "Create" title link above the real h1. The host's CustomCatalogPage and OpenChoreoScaffolderPage each mount their own PageWithHeader, while the NFS PageBlueprint's PageLayout emits another. Pass noHeader: true on the page:catalog and page:scaffolder overrides, and delete the now-redundant legacy <Route path="/catalog"> and <Route path="/create"> mounts (and their 27 field-extension imports) from App.tsx. Signed-off-by: Kavith Lokuhewage <kaviththiranga@gmail.com>
| <OpenChoreoCatalogEntityPage> | ||
| {entityPage} | ||
| </OpenChoreoCatalogEntityPage> | ||
| ); |
There was a problem hiding this comment.
We are replacing default entity page loader here, which means that the EntityContentBlueprint.make(…) declarations across the alpha files in plugins are ignored at render time . Every tab on the entity page comes exclusively from the EntityPage.tsx that we have written.
This contradicts with the purpose of EntityContentBlueprint declarations in the new frontend system, where the Entity page loader is supposed to read the registered pages in plugins viainputs.contents and render them.
Also now we have 2 declarations for each entity page tab (one contributed by the plugin alpha file and other in the EntityPage) and in order to actual get a new page rendered a developer need to edit our EntityPage.
There was a problem hiding this comment.
Yeah, that's deliberate. The page:catalog/entity override returns a fixed {entityPage} and intentionally doesn't read inputs.contents, so for this portal EntityPage.tsx stays the single source of truth for tabs.
The reason isn't the tabs — it's the cards. Each per-kind Overview composes a bespoke grid (EntityCatalogGraphCard, FailedBuildSnackbar, About/Links/Labels positioning, kind-specific layouts) and OpenChoreoEntityLayout adds the dropdown header and styled tab bar. inputs.contents only hands you a flat list of tab routes — no way to express "place these cards in this grid position on the Overview of kind:component, type:service." So the override is the trade: portal keeps its bespoke layouts.
The EntityContentBlueprint declarations in the plugin alpha files aren't dead — they're what external adopters get. A host that installs our plugins against the default upstream page:catalog/entity gets Build, Deploy, Logs, Events, Metrics, etc. mounted automatically via inputs.contents, no EntityPage.tsx required. The double-declaration is the price of supporting both: bespoke portal vs. batteries-included external host.
If we ever want third-party EntityContentBlueprints to appear here too, the override can switch to factory(originalFactory, { inputs }) and merge inputs.contents deduped by path — escape hatch noted at customOverrides.tsx:128-133.
There was a problem hiding this comment.
Its basically done to make the existing layouts work in our portal - but for external adopters, NFS path is recommended.
We need to rethink about the entity page layouts and possibly migrate our entity pages completely to EntityContentBlueprints - but that's a distraction I didn't want to drag into the migration task .
We can consider it post-migration.
Summary
Migrates the OpenChoreo Backstage portal from the legacy frontend system (
createAppfrom@backstage/app-defaults+<FlatRoutes>) to the New Frontend System (createAppfrom@backstage/frontend-defaults+features: [...]). The five custom OpenChoreo frontendplugins now ship a
/alphaNFS entry point alongside their legacy default export.This addresses the body of
openchoreo/openchoreo#3568 — adopters
can now drop
--legacyfrom the@backstage/create-appstep when installing the plugin suite.Cut on top of #614 (
8d8bd80f chore(deps): upgrade Backstage portal to v1.51.0).Changes
Plugin packages (5 ×
/alphaentry point)@openchoreo/backstage-plugin@openchoreo/backstage-plugin-openchoreo-ci@openchoreo/backstage-plugin-openchoreo-observability@openchoreo/backstage-plugin-openchoreo-workflows@openchoreo/backstage-plugin-platform-engineer-coreEach plugin's default export remains the legacy
createPlugininstance — the dev sandboxes(
plugins/*/dev/index.tsx) and any host on the legacy frontend keep working unchanged. The new/alphaentry exposes acreateFrontendPluginwithApiBlueprintextensions for theplugin's APIs and
PageBlueprint/EntityContentBlueprintextensions for the top-level pageswhere applicable. Routable extensions that the host currently mounts with per-call props (e.g.
<ObservabilityRuntimeLogs renderRowAction={...} />) stay on the legacy export for now — afuture PR will route those through a host-injected callable registry API so they can flow
through NFS too.
App shell (
packages/app)createAppimport to@backstage/frontend-defaults.convertLegacyAppOptions;legacy
<FlatRoutes>JSX tree flows throughconvertLegacyAppRoot.features, plus the upstream NFS plugins we need forroute ref resolution (
plugin-scaffolder/alpha,plugin-catalog-import/alpha).pluginIdviawithOverrides({ extensions: [getExtension(...).override({...})] }):api:catalog-graph→ adds OpenChoreo custom relations (deploysTo,usesPipeline,hostedOn,instanceOf, …).api:catalog/entity-presentation→ adds kind icons for Environment, DataPlane,DeploymentPipeline, ResourceType, etc.
api:scaffolder/form-decorators→ injectsopenChoreoTokenDecoratorfor user-basedauthorization on scaffolder actions.
page:scaffolder→ disabled so our legacy<ScaffolderPage>mount (withCustomTemplateListPageandCustomReviewStep) owns the page.DynamicSignInPageto an NFSSignInPageBlueprintextension inapis/customOverrides.tsx.__experimentalTranslations(catalog-import header customization) as aTranslationBlueprint.make({...})module.ScaffolderPreselectionProviderto wrap<Root>becauseconvertLegacyAppRootrequires the route element to BE the routable extension (no wrappers between).
ScaffolderLayout(CSS-only wrapper for card width constraint) — minor visualregression, deferred to a future CSS-scoped rule in
buiOverrides.css.Dependencies
@backstage/frontend-defaults@^0.5.2,frontend-app-api@^0.16.3,frontend-plugin-api@^0.17.0,core-compat-api@^0.5.11,plugin-app@^0.4.6,plugin-app-react@^0.2.3forward as direct deps ofpackages/app, plusfrontend-test-utilsas a dev dep. Collapses
@backstage/frontend-plugin-apifrom 8 nested copies → 1 hoisted (plus3 community-plugin-isolated copies of
^0.13.4that don't cross NFS boundaries).@backstage/frontend-plugin-api: ^0.17.0as a dep and anexports./alphamap entry.Known deferred items
Tracked for follow-up PRs after this lands:
<ScaffolderFieldExtensions>JSX blockrather than NFS
FormFieldBlueprintmodules. The two don't bridge while our custom<ScaffolderPage>mount owns/create— upstream'sFormFieldBlueprintattaches viaattachTo: { id: 'page:scaffolder', input: 'formFields' }, and we havepage:scaffolderdisabled. The proper rewiring needs
CustomTemplateListPage/CustomReviewStepto bere-authored as NFS overrides of
scaffolderTemplatesSubPage/scaffolderPage.<ObservabilityRuntimeLogs renderRowAction={...} />) and host-side wrappers like<FeatureGatedContent feature="observability">keep flowing through the legacy plugin exports. The NFS-nativerewiring needs a host-injected callable registry API for the props case and the blueprint's
if/filterslot for the gating case.openchoreo.github.ioinstall docs still recommendnpx @backstage/create-app --legacy.Will land as a separate PR on the docs repo (per the original migration plan's Phase 7 scope),
sequenced after this PR merges and the affected plugin versions release.
Summary by CodeRabbit