Skip to content

feat: add Backstage UI for resource abstractions#546

Draft
Mirage20 wants to merge 61 commits into
openchoreo:mainfrom
Mirage20:issue-3336
Draft

feat: add Backstage UI for resource abstractions#546
Mirage20 wants to merge 61 commits into
openchoreo:mainfrom
Mirage20:issue-3336

Conversation

@Mirage20
Copy link
Copy Markdown
Contributor

@Mirage20 Mirage20 commented May 15, 2026

Purpose

Adds Backstage UI support for the Resource Abstractions feature
(openchoreo/openchoreo#3336)


Resource Type Overview

res-type-overview

Resource Overview

res-overview

Cell Diagram with Resources

cell-diagram

Resource Creation Flow

resource_creation.mov

Workload Resource Dependency Management Flow

workload-wire.mov

Related Issues

Related openchoreo/openchoreo#3336

Checklist

  • Tests added or updated (unit, integration, etc.)

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a7818aea-cf1a-4788-a6a8-78559425929a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Mirage20 added 4 commits May 15, 2026 16:48
- Wire catalog ingestion: new Backstage kind, processor, translator,
  and OpenChoreoEntityProvider + EventDeltaApplier integration
- Add PlatformResourceService backend routes (GET/PUT/DELETE) for
  /api/v1/clusterresourcetypes via the typed openchoreo-api client
- Add Definition tab support via the generic ResourceDefinition flow
- Add Scaffolder create flow: action, template, custom YAML editor
- Add cluster-scoped permissions (create/update/delete) wired through
  openchoreo-common, openchoreo-react hooks, and the permission-backend
  policy rule
- Update PE/developer/SRE role templates in RoleDialog
- Add display polish: LayersIcon, gray color tokens, EntityPage route,
  catalog Create button, search modal icon, graph labels

Part of openchoreo#3336.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Wire catalog ingestion: new Backstage kind, processor (emits partOf
  Domain), translator, and OpenChoreoEntityProvider per-namespace fetch
  + EventDeltaApplier integration
- Add PlatformResourceService backend routes (GET/PUT/DELETE) for
  /api/v1/namespaces/{ns}/resourcetypes via the typed openchoreo-api
  client, plus VALID_PLATFORM_RESOURCE_KINDS entry on the router
- Add Definition tab support via the generic ResourceDefinition flow
- Add Scaffolder create flow: action, template, custom YAML editor
- Add namespace-scoped permissions (create/update/delete) wired through
  openchoreo-common, openchoreo-react hooks, and the permission-backend
  policy rules (matchesCapability NAMESPACE_SCOPED_KINDS,
  matchesCatalogEntityCapability KIND_TO_ENTITY_LEVEL, and
  OpenChoreoPermissionPolicy scaffolderCreateActions)
- Update PE/developer/SRE role templates in RoleDialog
- Add display polish: LayersIcon, gray color tokens, EntityPage route,
  catalog Create button, search modal icon, graph labels

Part of openchoreo#3336.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Pulls 24 upstream PRs since 2026-05-14 sync. Two openapi-touching changes:

- expose workload.dependencies.resources in the wire schema, including
  the new WorkloadResourceDependency type (openchoreo #3506) — unblocks
  Component.spec.dependsOn population for the resource-abstractions
  Backstage slice
- add ScopeResource as a sibling sub-scope under project, extending the
  authz ResourceHierarchy and TargetScope shapes (openchoreo #3448)

Regenerated TS client types; yarn tsc clean (no consumer adaptations
needed — both upstream changes are additive).

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Wire catalog ingestion for kind:Resource: translator, per-namespace
  fetch, EventDeltaApplier dispatch, and Component.spec.dependsOn
  population from workload.dependencies.resources[] so Backstage emits
  the Component -> Resource relation natively
- Add BFF endpoints (/resource-release-bindings, /resource-type-schema,
  /cluster-resource-type-schema) plus the resources arm on
  PlatformResourceService and transformResourceReleaseBinding
- Add openchoreoResource{Create,Update,Delete} permissions, the
  useResourceCreatePermission hook, and wire resource into existing
  permission maps (KIND_TO_PERMISSIONS, KIND_TO_ENTITY_LEVEL=component,
  scaffolderCreateActions, with opportunistic backfill of missing
  clustercomponenttype/clusterresourcetype create entries) plus
  PE/dev/SRE role templates
- Add the Resource entity page with three Overview cards (type and
  parameters, per-env binding summary, consuming components) via an
  EntitySwitch on the generic resourcePage so other plugins'
  kind:Resource entities keep the default layout
- Add the scaffolder create flow: openchoreo:resource:create action,
  template, and a two-step ResourceYamlEditor field extension
  (kind+name picker -> RJSF schema-driven form -> YAML composition)
- Add Storage and StorageOutlined icons across App.tsx, apis.ts,
  CustomTemplateCard, CustomSearchModal; add resource entries to
  graphUtils kind labels, DeleteEntity hooks, ResourceDefinition
  utils, the Platform Overview Developer Resources view, and the
  ALL_FILTERABLE_KINDS dropdown
- Extend buildScopeFilter in the policy backend so DB-level capability
  filtering narrows Resource entities by their PROJECT annotation

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Mirage20 added 23 commits May 16, 2026 16:12
- Add fetchResourceEnvironmentInfo BFF endpoint that joins environments,
  release bindings, project deployment pipeline, and Resource latestRelease
  into one per-env response
- Add updateResourceReleaseBinding (GET-or-POST-or-PUT upsert) and
  deleteResourceReleaseBinding BFF routes wrapping the openchoreo-api
  resourcereleasebindings CRUD; no openchoreo-api change required
- Propagate ResourceReleaseBinding status.outputs through the transformer
  with secret/configMap key references only (no resolved secret values
  cross the wire)
- Add resourcereleasebinding:update/create/delete permissions and matching
  React hooks for env-scoped permission checks
- Add split-pane Deploy tab on the Resource entity page: pipeline DAG
  canvas (reuses dagre + zoom infra from openchoreo-react) plus per-env
  detail panel with Promote, Deploy, Undeploy, and retainPolicy toggle
  actions
- Render outputs with type-aware formatting (value / secretRef Secret/x.y /
  configMapRef ConfigMap/x.y)
- Show "Behind" badge inline with the release pin when binding lags
  Resource.status.latestRelease
- Poll every 10s while any binding is mid-rollout (reuses Component-side
  useEnvironmentPolling hook)
- Add confirmation dialog for Undeploy that surfaces retainPolicy
  semantics (Retain holds via finalizer, Delete cascades)
- Update slice-3 ResourceBindingsCard to use design-system StatusBadge
  instead of raw MUI Chip for visual consistency with the Deploy tab

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…pe columns

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…mponent

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…esourceType

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…metersField

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…nwrap

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Add ResourceSetupCard leading tile on the deploy DAG (uses the shared
  setup node already emitted by buildEnvPipelineNodes)
- Add ResourceSetupDetailPane with the Configure & Deploy entry into the
  resource configuration wizard (wizard route lands in a follow-up)
- Mutually-exclusive selection between Setup tile and env tiles in the
  right-side panel
- Drop the redundant page-padding wrapper so the layout no longer
  overflows BackstageContent's own padding (matches Component side)

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Wraps the existing BFF /resource-type-schema and
/cluster-resource-type-schema routes that previously had no client API
exposure. Reads RESOURCE_TYPE + RESOURCE_TYPE_KIND annotations off the
Resource entity to pick the namespace-scoped vs cluster-scoped endpoint.
Consumed by the Step 1 wizard landing in the follow-up commit.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Extract the existing deploy view into ResourceEnvironmentsList so the
  /environments tab can host sub-routes
- Make ResourceEnvironments a thin Routes wrapper with two paths: / for
  the deploy view, /parameters-config for the new wizard
- New ResourceParametersConfigPage renders an RJSF form against the
  (Cluster)ResourceType schema. Save & Close PUTs the Resource via the
  existing platform-resource update path; the controller auto-cuts a
  new ResourceRelease from the spec hash change
- Wire the Set up panel's Configure & Deploy button to navigate into the
  new wizard route
- Tests updated to wrap in MemoryRouter and target the extracted list

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Passes the per-environment override map through the binding GET path so
callers can read existing overrides off a ResourceReleaseBinding.
Mirrors the symmetry already present on the Update side, which has
accepted the field in the body since the binding's REST surface landed.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- New ResourceEnvironmentOverridesPage renders an RJSF form against the
  (Cluster)ResourceType schema, with Save / Clear actions that PUT the
  ResourceReleaseBinding with resourceTypeEnvironmentConfigs
- New ResourceEnvironmentOverridesWrapper mounts the page under
  /environments/overrides/:envName; Back uses path-relative navigation
  so it lands on the deploy view instead of climbing the parent route
- Detail panel grows a Configure overrides action that navigates with
  env.resourceName (the K8s ref the binding lookups key on)
- Existing parameters-config wrapper switched to the same path-relative
  back navigation for consistency
- Detail panel test wraps in MemoryRouter for the new useNavigate hop

Override pre-population on load is deferred — the wizard currently
starts fresh; persisted overrides land on the binding either way.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- New BFF endpoint /resource-release-schema?namespaceName=&releaseName=&section=
- Returns the openAPIV3Schema for either the parameters or
  environmentConfigs section snapshotted on the ResourceRelease
- Frontend client wrapper fetchResourceReleaseSchema(namespace, release, section)
- Pinned-release flows now validate against what the release was cut
  against, not the live (Cluster)ResourceType which may have drifted

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Configure Resource wizard's Next button PUTs the Resource then polls
  fetchResourceEnvironmentInfo every 1s up to 30s until the
  controller-cut release name differs from the pre-save baseline, then
  navigates to the overrides wizard pinned to that release
- Skips PUT+poll when parameters are unchanged; still chains forward
  with the existing release name
- Overrides wizard accepts a releaseFromUrl prop that pins the binding
  to the URL-specified release on save and labels the primary action
  Deploy instead of Save Overrides
- Schema now comes from the pinned release's snapshot
  environmentConfigs section (was: live ResourceType parameters), so
  the form matches the contract the controller actually renders against
- Edit-mode entry from the env detail panel is unchanged

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Overrides wizard now fetches fetchResourceReleaseBindings on load,
  finds the binding for the current env, and seeds the form with the
  stored resourceTypeEnvironmentConfigs map. Returning to the wizard
  shows the values the user previously saved instead of an empty form.
- Both wizards capture the first RJSF onChange as the change-detection
  baseline. RJSF normalizes formData on initial render (expanding schema
  defaults for missing fields), so treating that normalized snapshot as
  the baseline keeps hasChanges accurate to what the user actually typed.
- Track a separate hasActualOverrides flag from the backend's
  perspective so Clear Overrides reflects whether overrides exist on
  the binding, not whether the form differs from schema defaults.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
The form-initialized ref was being reset to false on every load, which
made the user's first real edit get captured as the baseline whenever
the backend already had values to seed the form with. Result: Save
stayed disabled even after unticking a populated checkbox.

Only allow the RJSF-normalization capture when the backend payload was
empty (the case where mount-time default expansion needs to be absorbed
into the baseline). When there are stored values, those values are the
baseline directly. Same fix in both wizards.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Mirage20 added 30 commits May 17, 2026 11:02
- Read the Ready condition's lastTransitionTime as the env-info
  lastDeployed timestamp. The aggregate Ready flips on each successful
  Resources reroll after a promote, so per-env cards now show a real
  per-promote signal instead of all bindings reporting the same
  creationTimestamp.
- Synced alone was unreliable: its message embeds the RenderedRelease
  name which is binding-stable across promotes, so SetStatusCondition
  saw the message as unchanged and never refreshed the timestamp on
  subsequent renders.
- Falls back to creationTimestamp on bindings the controller has not
  yet reconciled.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Suppress the catch-clause setSaveError when cancelledRef is set so a
  navigate-during-save does not trip React's unmounted-component
  warning.
- Add an inline info Alert when fetchResourceEnvironmentInfo returns
  zero envs. The Continue button is correctly disabled in that case,
  but until now the user had no signal explaining why; the banner
  points to the deployment pipeline as the missing piece.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Start with no env selected; render an empty-state hero with the
  AllInbox icon and copy "Select an environment to view details, or
  click Set up to update configuration." Clicking empty canvas space
  deselects the currently active card.
- Update the Set up panel subtitle to describe what Configure &
  Deploy actually does ("Manage resource configuration and deploy a
  new version.") instead of the misleading project-scoped wording.
- Add a View release manifest modal that fetches the ResourceRelease
  CR and renders the snapshot as YAML. Reachable from both the env
  card 3-dot menu and the Release row in the detail panel; disabled
  when no release is pinned on the env.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Pushes the current env's release forward to the next env(s) in the
pipeline. Mirrors Component: direct Promote button when there is a
single promotion target, Promote dropdown with per-target items when
there are several, and a disabled Promoted state when every target
already has this release. Hidden when the env has no binding or no
promotion targets (last env).

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
The side panel's inline outputs list was cramped at 380px — long
values like the postgres host FQDN and adminURL wrapped across
several lines. Replace the inline list with an Outputs (N) header +
View All link that opens a roomier modal. Each output renders in its
own block with a kind chip (VALUE / SECRETREF / CONFIGMAPREF), the
value or ref in a wrappable monospace box, and a per-row copy
button. Deletes the now-unused ResourceOutputsList component since
the modal is the only display surface.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Link http(s) values so admin URLs and dashboards open in a new tab
  on click. Non-URL values stay as plain monospace text.
- Hide Secret / ConfigMap references behind a per-row Show reference
  toggle. Defaults to a short "Stored in Secret" / "Stored in
  ConfigMap" placeholder so the K8s ref shape, which is internal
  plumbing for developers, doesn't crowd the modal. Expanding reveals
  the Kind/name.key string with a copy button for SRE debugging.
- Drop the VALUE / SECRETREF / CONFIGMAPREF chips and inline the
  reference toggle on the right of the output name. The placeholder
  text already names the kind for refs, and value outputs don't need
  a chip to identify a visible value.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
The destructive surface (retainPolicy toggle + Remove deployment)
moves into a collapsed-by-default Danger zone accordion at the
bottom of the panel, mirroring Component. Inline retainPolicy row
and Actions-row Undeploy are dropped so the panel has a single
destructive surface.

- retainPolicy: gates Remove deployment. Retain disables the button
  with "Set retain policy to Delete to allow removal." tooltip.
  Switching Retain → Delete pops a confirm dialog warning that
  stored data may be lost; Delete → Retain applies one-click.
- Remove deployment: outlined error-tinted button. Confirm dialog
  explains the binding + overrides + underlying K8s teardown,
  with the "stored data may be lost depending on the resource type
  implementation" qualifier so we don't over- or under-promise.
- BFF resolves effective retainPolicy by fetching the referenced
  (Cluster)ResourceType and applying the chain: binding override →
  ResourceType default → built-in Delete. Soft-fails on fetch error
  so a transient API issue never blocks the env-info response.
- Danger zone styling matches Component: alpha-tinted red background
  and border, error.dark for icon + title.

Replaces the old UndeployConfirmDialog with a Resource-flavored
ResourceRemoveDeploymentDialog and adds a small
ResourceRetainPolicySwitchDialog for the Retain → Delete confirm.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Card and detail panel now show the same Promote button state for
the same env: both promote this env's release forward to the next
env(s) in the pipeline (mirrors Component). Drops the old panel
behind-latest semantic — the panel no longer shows a separate
"advance-to-latest" Promote.

- New computeResourceReleaseDrift helper ports Component's release-
  name equality against direct upstreams. Drift map is computed
  once in ResourceEnvironmentsList and threaded through context.
- Env card surfaces a lowercase "behind" badge with a warning-tinted
  background when at least one direct upstream is on a different
  resourceRelease. Tooltip lists the upstream env and its release
  name.
- Panel drops the behind-latest badge. Panel Promote reads plain
  "Promote" (matches Component) but routes through the same handler
  as the card so the action is consistent across surfaces.

Spec edit drift on the first env (Dev edited via kubectl without
a promote) intentionally falls out of this signal; the canvas Set
up flow is the entry point for first-deploys and re-deploys.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Rewrites the panel layout to mirror Component's visual rhythm so the
two surfaces feel like the same product.

Header
- Restructure to two rows: CloudIcon + env name + refresh/close on
  top, StatusBadge on its own row below. Drops the inline name +
  badge layout.
- Drop the header borderBottom; per-section borderTop now provides
  the dividers.
- Use an explicit envName fontSize/ellipsis class instead of
  variant=h6 (which is theme-dependent). Drop the redundant
  Tooltip wrapper around Refresh.

Body + sections
- Body has padding 0 + overflowY auto; sections own their own
  padding spacing(2, 2.5) + borderTop, producing full-width
  horizontal dividers between Release, Outputs, Actions, and the
  Danger zone.
- Section title typography becomes the uppercase 0.78rem caption
  style (textTransform: uppercase, letterSpacing 0.6, fontWeight
  600) replacing the body2 fontWeight 500 pattern.
- metaRow loses its per-row padding now that section gap handles
  spacing.

Release row
- Drop the 140px grid layout. Release and Deployed are now inline
  flex rows where the small caption label sits next to the value.
- Release name uses a monospace caption with ellipsis at 280px and
  a tooltip showing the full name on hover.
- View release icon now precedes Copy (Component order). Icons
  use fontSize=inherit so they match the caption baseline.
- Deployed value uses body2 / text.secondary instead of monospace.

Section layout
- Drop the standalone Configuration section entirely. Configure
  overrides moves into Actions, sitting right-aligned next to
  Promote in the section title row.
- Reorder so Outputs sits above Actions.
- Style Configure overrides as outlined primary with
  SettingsOutlinedIcon and textTransform=none, matching Component.

Setup pane
- Add dedicated setupHeader (with borderBottom) + setupBody (with
  padding) so the Set up tile's right pane reads as a single body
  of prose + action button instead of trying to use the env
  panel's padding-less body. Mirrors Component's split.

Danger zone
- Sits in its own section so the borderTop divider + section
  padding give Component-style breathing room between the Actions
  buttons and the destructive surface. Drop the now-redundant
  marginTop and expanded-state margin override on the accordion.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
The card and panel Promote handlers passed target.name (the env
display name like "Production") to onPromote, which the BFF then
stitched into a binding metadata.name like "orders-db-Production".
The K8s apiserver rejects that with 422 because RFC 1123 subdomain
names must be lowercase.

Prefer target.resourceName ?? target.name everywhere promote is
initiated — single-target click on card and panel, multi-target
dropdown items, and the in-flight detection (pendingAction.env is
now the resource name so the "Promoting..." state also keyed on the
resource name). isTargetAlreadyPromoted keeps using the display
name since it looks up against environments[].name which is the
display name.

Regression test asserts promote sends `production` when the target
exposes both `name: "Production"` and `resourceName: "production"`.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Coerce env.resourceName ?? env.name at every BFF call site for undeploy
  and retain-policy toggle (handleUndeployConfirm + handleRetainPolicyChange).
  Lookups and pendingAction now key off the resource name, mirroring the
  promote precedent in 68d268c. isRemoving on the confirm dialog and
  isUndeploying/isUpdatingRetainPolicy in the detail panel updated to the
  same comparator so the "Removing..." button state and busy guards still
  trigger.
- Add a verification poll in handleUndeployConfirm: after DELETE returns,
  poll fetchResourceEnvironmentInfo every 1.5s for up to 15s and only fire
  the success toast when the env reports no binding. Catches both the BFF
  silent-success case and the Resource controller's two-phase finalizer
  deferring cluster-side removal for several seconds.
- Pre-flight GET in BFF deleteResourceReleaseBinding so a wrong-name DELETE
  surfaces as 404 instead of the openchoreo-api's 204 over a no-op. Defense
  in depth for the same bug class as the frontend coercion.
- Drop the Reason row from the NotReady panel and switch Message to the
  Release-row pattern: caption label, truncated value with ellipsis, full
  text in hover tooltip, copy button. Replaces the two-column metaRow
  layout whose 140px label + wordBreak: break-all chopped values
  mid-token at the panel's ~150px value width.
- Two regression tests (undeploy + retain) lock in resourceName vs name
  for the client call; one new BFF test covers the pre-flight 404 path
  and the existing happy path test updated to mock the GET first.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
The catalog list's `Create Resource` button still pointed at the
deleted create-openchoreo-resource scaffolder template, surfacing
the pre-slice-5b wizard (orphan textbox, "Create a new component"
tab title) instead of the per-type browse pattern Component already
uses.

- useKindCreateConfig.ts: resource case routes to
  ${scaffolderRoot}?view=resources, mirroring the component case.
- app-config.yaml / app-config.production.yaml: drop the dangling
  scaffolder location entries that targeted the deleted
  templates/create-openchoreo-resource/template.yaml. Stops backstage
  from re-ingesting the cached entity on every restart.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Sort the platformTemplates list by PLATFORM_TYPES index so the order
becomes explicit instead of relying on the catalog-list response
order. Reshuffles the array into a foundation-first layout matching
Application Resources (Project → Component → Resource):

  Namespace → Environment → Deployment Pipeline
  → ClusterComponentType → ComponentType
  → ClusterTrait → Trait
  → ClusterResourceType → ResourceType
  → ClusterWorkflow → Workflow

Cluster-scoped sits before namespace-scoped within each pair so the
pairs stay adjacent and read "platform-wide template → namespace-local
variant". Topology types come first (foundation, one-time bootstrap),
then template types grouped by concept — workload shape, cross-cutting
concerns, infra deps, automation.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
The workload editor's three endpoint dependency handlers each wrote
`dependencies: { endpoints: ... }` wholesale, dropping any
`dependencies.resources[]` already on the workload. A developer who
added or edited an endpoint dep on a workload with resource deps wired
in YAML would silently lose every resource dep on save.

- Add a single `updateDependencies({ endpoints?, ... })` helper that
  merges the patch into the existing `dependencies` object so the other
  side survives.
- Rewire the three endpoint handlers (replace / add / remove) to use it.
- Add a new `WorkloadEditor.test.tsx` covering the three handler paths
  plus the no-resources happy path.

The same helper is the seam future resource-dep handlers will hook into,
so the symmetric bug (endpoints dropped on resource edits) cannot be
reintroduced.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
The dirty-state hook only diffed `dependencies.endpoints`, so mutations
to `dependencies.resources[]` were invisible to it. Save buttons and
unsaved-changes prompts wouldn't fire on resource-dep edits even though
the workload had changed.

- Extract `diffNamedArray` so endpoint and resource diffs share the same
  add/remove/modify walk.
- Add `resourceDependencyLabel` (returns the ref) and a parallel resource
  diff call; merge the result into the existing dependencies bucket.
- New `useWorkloadChanges.test.ts` covers add / remove / modify / mixed
  endpoint+resource / no-change cases.

Forward-guards the read-only resource-dep display so its dirty-state
plumbing isn't sitting on a silent landmine.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Developers can now see `Workload.spec.dependencies.resources[]` entries in
the Dependencies tab. Editing still happens via the YAML view; the
inline editor lands with the two-button Add bar in a follow-up.

- Add `ResourceDependency` type alias in openchoreo-common that re-exports
  the generated `WorkloadResourceDependency` shape.
- New `ResourceDependencyDisplay` component in openchoreo-react renders a
  resource entry as a read-only card with a `Resource` chip and lists
  envBindings and fileBindings as `output → target` rows.
- `DependencyList` accepts an optional `resources` prop and renders the
  display rows below the existing endpoint rows.
- `DependencyContent` and `WorkloadEditor` pass `formData.dependencies.resources`
  through. The Dependencies tab count badge counts both endpoint and
  resource entries.
- Drop hardcoded `dependencies: { endpoints: [] }` from the new-workload
  default in `WorkloadConfigPage`; an undefined dependencies block
  produces no diff and matches the Resource side's shape.

Tests: 5 ResourceDependencyDisplay specs covering ref + chip rendering,
env/file binding rows, and empty bindings; 1 new WorkloadEditor spec
locking in that both endpoint and resource counts reach DependencyContent.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Endpoint dependency rows now carry a small outlined `Component` chip in
their read-only display, matching the `Resource` chip on resource rows.
The two row types are now visually distinguishable when the editor
renders mixed dependencies (or once 9c/9d add a second add-button and
inline resource editor).

New DependencyEditor.test.tsx covers the chip's presence and the
component-name fallback path.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…itor

The upcoming resource-dependency editor needs to enumerate the outputs a
ResourceType declares so it can render one row per output with the
appropriate env/file binding controls. The openchoreo-api already serves
the full (Cluster)ResourceType via GET, so this adds a thin BFF wrapper
that extracts spec.outputs and a frontend client method that dispatches
by RESOURCE_TYPE_KIND annotation.

- New fetchResourceTypeOutputs on ResourceTypeInfoService and
  fetchClusterResourceTypeOutputs on ClusterResourceTypeInfoService;
  both call the existing GET and return spec.outputs (empty array
  when absent).
- New /resource-type-outputs and /cluster-resource-type-outputs router
  endpoints mirroring the schema routes.
- New ResourceTypeOutput type and fetchResourceTypeOutputs(entity) on
  OpenChoreoClient, dispatching on the Resource entity's
  RESOURCE_TYPE_KIND annotation the same way fetchResourceTypeSchema
  already does.

Tests: 6 new service specs (happy path, empty outputs, upstream error)
across both BFF services.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…indings

The component renders a list of wired outputs for a single resource
dependency, with per-row env-var name and mount-path fields and a
bottom `+ Add binding` dropdown listing the (Cluster)ResourceType's
remaining unbound outputs. Mount-path is disabled for value-kind
outputs since the backend rejects mounting value-kind values as files.

- New `ResourceTypeOutput` alias in openchoreo-common re-exports the
  generated `WorkloadResourceDependency`/`ResourceTypeOutput` shapes.
- `ResourceDependencyEditor` in openchoreo-react: controlled component
  (state lives in parent), emits the updated dependency on every
  change, supports add / edit / remove for both binding maps.
- Empty target values are tolerated mid-edit so users can type freely;
  validation gating happens upstream where save logic lives.

Component is built in isolation here — wiring into DependencyList
(two `+ Add` buttons + row dispatch) and into WorkloadEditor (the
new handlers and BFF-driven outputs fetch) ship in the follow-up.

15 specs cover rendering, field edits, remove (both row-level and
top-level), and the Add-binding dropdown (unbound-only listing, new
row creation, disabled-when-empty state).

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Completes the resource-dependency story in the workload editor. The
Dependencies tab now exposes the same CRUD surface for
`dependencies.resources[]` as it has for `dependencies.endpoints[]`:
two add buttons at the bottom (`+ Add Component Dependency` and
`+ Add Resource Dependency`), inline editors per row, and a picker
dropdown that lists project-owned Resource entities not yet bound.

- New handlers `handleResourceDependencyReplace`, `addResourceDependency`,
  `removeResourceDependency` on WorkloadEditor, all going through the
  `updateDependencies` helper so endpoint deps survive resource edits.
- `updateDependencies` signature extended to accept `{ resources }`.
- DependencyContent lists project Resource entities from the catalog
  and fetches outputs[] for each wired ref via the BFF endpoint added
  in the previous commit; results cached by ref so FORM<->YAML mode
  switches don't re-fetch.
- DependencyList swapped from the read-only `ResourceDependencyDisplay`
  to the editable `ResourceDependencyEditor` (built in isolation in
  the previous commit); two `+ Add` buttons replace the single one.
- WorkloadEditor.test.tsx adds the symmetric regression test: endpoint
  deps survive resource-dep add / replace / remove.

Live-validated on `orders-api`: existing orders-db + orders-cache deps
render as editable rows with their bindings; picking `orders-events`
from the dropdown appends a new row; YAML view confirms all three
resources end up in `spec.dependencies.resources[]`.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
The Dependencies tab now treats resource dependencies the same way it
treats endpoint dependencies: each row collapses to a compact one-line
summary in read-only mode and expands into a full per-output binding
form when Edit is clicked. Apply commits the buffered changes; Cancel
discards them (and removes new rows). At most one row across either
type can be in edit mode at a time, and the Add buttons + every other
row's Edit/Remove button are disabled while editing.

Also moves both Add buttons to the top of the list so they stay visible
regardless of how many dependencies the workload accumulates.

- New useResourceDependencyEditBuffer hook in openchoreo-react mirrors
  the endpoint side's hook with resource-specific validity (ref present,
  no empty binding targets).
- ResourceDependencyEditor accepts isEditing/onEdit/onApply/onCancel
  props; read-only render shows ref + Resource chip + "N env, M file
  bindings" summary + Edit + Remove buttons; edit render keeps the
  existing per-output binding form and adds an Apply/Cancel/Remove
  footer.
- DependencyList wires the new resource buffer alongside the endpoint
  buffer; `anyRowEditing` ORs both states so cross-type editing is
  blocked.

Tests: 15 ResourceDependencyEditor specs cover both modes (read-only
summary + button clicks; expanded edit fields + apply/cancel + add-binding
dropdown + applyDisabled gating).

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Two small polish items to bring ResourceDependencyEditor visually flush
with the endpoint DependencyEditor:

- Drop the leading StorageIcon from both read-only and edit modes; the
  endpoint editor has no icon and the Resource chip already conveys the
  type.
- Move Apply / Cancel / Remove from a bottom row of named buttons to a
  right-side vertical IconButton stack (Check / Close / Delete) matching
  the endpoint editor's edit-mode layout, including aria-labels.

Pure visual cleanup; no behavior change. Existing 15 specs still green
because the action buttons are queried by accessible name.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Align resource-dep add flow with the endpoint-dep flow: clicking
`+ Add Resource Dependency` now drops an empty row into edit mode and
the user picks the resource via a Select dropdown inside the row's
form (mirroring how endpoints are picked via Project / Component /
Endpoint dropdowns). The old behavior — a popover Menu off the Add
button — is gone.

- DependencyList drops the Menu/anchor state; the Add button calls
  `onAddResourceDependency('')` and starts the buffer with no initial.
  Each rendered editor row receives `availableResources` filtered to
  exclude refs claimed by OTHER rows so duplicates don't appear.
- ResourceDependencyEditor accepts `availableResources` (ResourceOption
  shape) and renders an outlined Resource Select in the edit-mode
  header. The selected ref always remains in the option list so users
  don't lose their pick when the parent's filter excludes it.
  Switching the ref clears `envBindings` and `fileBindings` — outputs
  are per-ResourceType, so existing bindings don't transfer.
- DependencyContent now pre-fetches outputs for every project Resource
  entity (not just wired ones) so picks render the right form instantly.

Tests: 3 new specs for the in-row picker (options listed,
ref-change emits cleared bindings, current ref stays selectable).
All 18 ResourceDependencyEditor specs green.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…ttons

A binding row used to render both an env-var field and a mount-path
field regardless of how the developer intended to wire the output. The
single "Add binding" handler inserted the picked output into
`envBindings` with an empty value, which made it impossible to add a
file-mount-only binding cleanly (the empty env entry would block
Apply, and the user had no obvious way to drop it).

Replaces the single Add button + Menu with two:
- `+ Add env binding` — lists any output not currently in envBindings.
  All kinds are eligible.
- `+ Add file mount` — lists outputs not currently in fileBindings,
  filtering out value-kind outputs (the backend rejects mounting a
  literal value as a file).

Each handler adds the output to its target map only; the row renders
only the fields actually wired. An output bound in both maps shows
both fields side by side as before.

Tests updated: 4 specs cover the two dropdowns (env list excludes
already-bound; file list excludes already-mounted and value-kind);
the previous "renders both fields" test is replaced by two narrower
specs locking env-only and file-only rendering. 21 specs total green.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
…g on empty

Two related fixes:

- For an output wired in both envBindings and fileBindings, there was no
  way to remove just one kind — the row-level trash dropped both. Adds a
  small ✕ icon next to each wired field; clicking it removes only that
  binding kind from its map.
- Clearing a field used to silently auto-delete the binding, which was
  surprising during edits ("I just wanted to retype, why did my binding
  disappear?"). Field edits now set the value as-is, including empty
  strings; empty values keep the buffer invalid (Apply disabled) until
  the user fills them in or explicitly clicks the ✕.

The asymmetry between adding (inserts empty, requires fill) and
clearing (silently removed) is gone — both add and remove are now
explicit actions.

Tests updated: 1 spec replaced (no-auto-delete on empty), 2 new specs
locking in per-kind remove behavior. 23 specs total green.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Walk workload.spec.dependencies.resources[] in CellDiagramInfoService
  alongside endpoints[], emitting one ConnectionType.Datastore connection
  per resource dep with onPlatform: true
- @wso2/cell-diagram auto-synthesizes a DatabaseIcon-styled node per
  Datastore connection (projectUtils.js:237-243, ConnectionHead.js:44)
  and routes edges through its connection-node namespace, so no resource
  node emission is needed on our side
- Switch internal types from hand-rolled bff-types (WorkloadResponse /
  Dependency / WorkloadEndpoint / ComponentResponse) to generated OpenAPI
  schemas via @openchoreo/openchoreo-client-node, aligning with the rest
  of the codebase (WorkloadEditor, resource-dependency editor, etc.)
- Fix latent mock-queue leak in CellDiagramInfoService.test.ts: test 4
  enqueued a 3rd error mock that bled into test 5 because clearAllMocks
  does not drain mockResolvedValueOnce queues

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Mirror ComponentTypeOverviewCard shape with kind-aware title
- Side-by-side Parameters / Outputs with name + type/kind columns
- Recursive flatten for nested params (dot-paths) and array types
- Synthesize ref-entity to call existing fetchResourceType{Outputs,Schema}
- Wire into resourceTypePage + clusterResourceTypePage Overview tabs

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Add ResourceEntityProcessor mirroring ComponentEntityProcessor
- Read RESOURCE_TYPE + RESOURCE_TYPE_KIND annotations, emit
  INSTANCE_OF + HAS_INSTANCE both directions
- Populates Relations graph on (Cluster)ResourceType pages with
  consuming Resources, and Resource pages with their type
- 4 new processor tests

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
- Convert ResourceEnvironmentDetailContent to function declaration for hoisting
- Flatten nested ternaries in OverridesPage, MiniEnvironmentNode, ParametersConfigPage
- Add missing setSelectedEnvName to useMemo deps in ResourceEnvironmentsList

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Pre-existing prettier drift across 47 files was masked by failing
eslint in earlier CI runs (eslint step short-circuited before
prettier --check ran). Now that eslint is green, run
`yarn prettier --write .` to clear the remaining 'Check formatting'
job. Pure cosmetic; no logic changes.

Signed-off-by: Miraj Abeysekara <miraj@wso2.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant