Workstream B wave 1: 5 signal-native page migrations#5323
Merged
norman-abramovitz merged 9 commits intocloudfoundry:developfrom May 11, 2026
Merged
Workstream B wave 1: 5 signal-native page migrations#5323norman-abramovitz merged 9 commits intocloudfoundry:developfrom
norman-abramovitz merged 9 commits intocloudfoundry:developfrom
Conversation
Drops Store + entityCatalog.getEntity + selectDeletionInfo + RouterNav dispatch. Delete confirm now awaits CfOrgsSignalConfigService.deleteOrg(cfGuid, orgGuid) — the same signal-native write path used by the org wall — then router.navigate back to the orgs list. Errors surface via TailwindSnackBarService. The deleteOrg method already existed on the signal-config service (shipped with the org wall). No shared infra changes.
Mirror of the org-summary migration. Drops Store + entityCatalog.getEntity + selectDeletionInfo + RouterNav dispatch. Delete confirm now awaits CfSpacesSignalConfigService.deleteSpace( cfGuid, spaceGuid) — already shipped with the org-spaces L5 migration — then router.navigate back to the org-spaces list. deleteSpace hits DELETE /pp/v1/cf/spaces/:cnsiGuid/:spaceGuid via writeWithJob (async-job polling) then refresh(). No shared infra changes.
Finishes the partial signal migration of the add-route stepper. Removes Store<CFAppState> injection plus the two RouterNav dispatch calls (replaced with inject(Router) + router.navigate). Drops cfEntityCatalog.space.store.getEntityService include-chain — the domain list now reads applicationService.orgDomains$ via toSignal. The space_guid the legacy chain side-effected is now captured by a small waitForAppEntity$ subscription. Domain auto-pick (first domain) is guarded so a later orgDomains$ re-emit can't clobber a user pick. Spec drops Store + RouterNav mocks, spies on Router.navigate from provideRouter.
Cells data is Diego cell rep-health metrics scraped from the firehose, not a CF v3 resource. Backend metrics endpoint (/pp/v1/metrics/cf/cells/query) was already in place — this is a frontend-only migration. Adds CfCellsSignalConfigService owning the Prometheus query with HEALTHY -> HEALTHY_DEPRECATED probe fallback (Diego v2.31+ vs older) and a tri-state availability() signal that replaces the legacy hasCellMetrics$ Observable gate. Adds CloudFoundryCellsSignalComponent mirroring the cf-stacks signal pattern. Route swap in cloud-foundry-section.routes.ts. Legacy cloud-foundry-cells.component + cf-cells-list-config.service + cf-cells-data-source deleted (no remaining consumers; cell-detail sub-routes still use CloudFoundryCellService and are out of scope).
Migrates the app-detail Variables tab from the legacy IListConfig +
ngrx Store dispatch pattern to signal-native. The new
CfAppVariablesSignalConfigService derives a Signal<ListAppEnvVar[]>
from AppDetailDataService.envVars().environment; the new
AppVariableActionsService owns add/update/delete writes that PATCH
/pp/v1/cf/apps/{cnsi}/{app} with the merged environment_json map
(matching the legacy AppVariablesUpdate semantics).
The component drops IListConfig + Store + cfEntityCatalog.appEnvVar
+ the legacy appService.appEnvVars paginator. Delete row action
goes through a confirm dialog. Inline Add form preserved with
on-submit validation; on save it calls actionsService.addVariable
then dataService.refresh('envVars').
Inline edit-in-place (TableCellEditVariableComponent) is dropped
in this slice; updateVariable is wired and a re-prefilled Add form
would restore that affordance — follow-up. Legacy
cf-app-variables-list-config.service + data-source files are now
dead code, kept in tree for now.
PR cloudfoundry#5322 merged the orgDomains$ type flip from Observable<APIResource<IDomain>[]> to Observable<StDomain[]> and the wrapDomain shim was deleted. This branch's add-route commit was written before that merge per the original brief. Updates the add-route component's domain reads to the flat shape: - domain.metadata.guid -> domain.guid - domain.entity.router_group_type === 'tcp' -> domain.supportedProtocols?.includes('tcp') ?? false - Drops APIResource + IDomain imports; uses StDomain throughout.
|
PR CI caught two leftovers from the wave-1 rebase:
- Template's TCP/HTTP branching read selectedDomain?.entity?.router_group_type
(the v2 envelope path); now reads selectedDomain?.supportedProtocols?.includes('tcp').
- Spec mocks built domain values as { metadata, entity } envelopes; now
build them as flat StDomain { guid, supportedProtocols }.
Local vitest run passes 16/16 add-routes tests.
Mirrors the done space-users migration. Adds an org-scoping mode to CfUsersSignalConfigService (initializeForOrg + _lockedOrgGuid signal); the users computed filters to users with at least one org-role bucket OR one space-role bucket carrying the target orgGuid. Precedence: space lock > org lock > unscoped. Component drops the legacy CfOrgUsersListConfigService provider plus the ngrx-paginator pipeline (addRolesByUsernameLink$, ListComponent, NoContentMessage, PageSubNav, CfAdminAddUserWarning, CloudFoundryInviteUserLink imports). Renders 5 columns: Username, Origin, Org Roles for THIS org, Space Roles narrowed to spaces under THIS org, Created. Template now app-list-sub-nav + app-signal-list. Legacy cf-org-users-list-config.service + spec deleted (no remaining consumers). Spec rewritten to assert initializeForOrg called with cnsi+orgGuid and column shape narrowing.
Component had eight Observable<boolean> fields (connecting$, valid$, isBusy$, etc.) declared but never assigned — the | async pipes in the template were always undefined, so the loading bar / error banner / submit-disable were effectively static. Rewritten to actually drive UI state: signal()s for showSecret, isBusy, hasErrored; toSignal(form.statusChanges) for formStatus; computed() for formValid + canSubmit. submit() now toggles busy/error state during the configure call and surfaces failures via sticky red snackBar.error(). Template drops | async pipes for signal calls; show-secret toggle moves to a method; Cancel button gets type="button" so it doesn't accidentally submit; submit button binds [disabled]="!canSubmit()". UserInviteService public surface unchanged — left alone since it was already clean (HttpClient, no Store/ngrx coupling) and has multiple downstream consumers.
norman-abramovitz
approved these changes
May 11, 2026
Contributor
norman-abramovitz
left a comment
There was a problem hiding this comment.
The PR hopefully covers the remaining stratos-to-backend-to-capi v3 conversion, and the front is 90% using Angular 21 signals instead of observables. The next PR does the auditing and removes the V2 frontend shims.
38b5a73
into
cloudfoundry:develop
11 of 12 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Five parallel signal-native consumer migrations from Workstream B. Each replaces the legacy ngrx-paginator/
cfEntityCatalogpattern with the established*-signal-configservice + signal component pattern.entityCatalog.getEntity+selectDeletionInfo+RouterNavdispatch toCfOrgsSignalConfigService.deleteOrg(...)+router.navigate. Service method already existed (org wall).CfSpacesSignalConfigService.deleteSpace(...)(already shipped with org-spaces L5).Store+cfEntityCatalog.space.store.getEntityServiceinclude-chain in the add-route stepper. Domain list now readsapplicationService.orgDomains$viatoSignal. Domain shape is the develop-current flatStDomain(not the legacyAPIResource<IDomain>)./pp/v1/metrics/cf/cells/querypassthrough. NewCfCellsSignalConfigServicewith HEALTHY → HEALTHY_DEPRECATED probe fallback (Diego v2.31+ vs older) and a tri-stateavailability()signal replacing the legacyhasCellMetrics$Observable gate. Legacycloud-foundry-cells.component+cf-cells-list-config.service+cf-cells-data-sourcedeleted.IListConfig+cfEntityCatalog.appEnvVar+ the legacyappService.appEnvVarspaginator. NewCfAppVariablesSignalConfigServicederives the var list fromAppDetailDataService.envVars(). NewAppVariableActionsServiceowns add/update/delete viaPATCH /pp/v1/cf/apps/{cnsi}/{app}with mergedenvironment_json(matches legacyAppVariablesUpdatesemantics).No shared infra changes —
CfOrgsSignalConfigService.deleteOrgandCfSpacesSignalConfigService.deleteSpacealready existed;AppDetailDataService.envVars()already exposed the read signal needed.Test plan
bunx tsc --noEmit -p packages/cloud-foundry/tsconfig.lib.jsoncleanStOrg.name, Delete button present, no console errorsCloudFoundryCellsSignalComponentand renders the legacy "metrics not found" empty state when the firehose endpoint isn't deployed (correct tri-state)make check gate— to be batched with subsequent B-wave PRsNotes
orgDomains$. After rebase onto develop (which merged Workstream A wrap-up: app-detail native handlers + apps OrgGUID #5322), a fixup commit flips it to the flatStDomainshape. Will be squashed on merge.TableCellEditVariableComponent) is dropped from the Variables tab in this slice;actionsService.updateVariableis wired so a re-prefilled Add form would restore that affordance — small follow-up.cells/:cellId/{summary,charts,apps}) still use the legacyCloudFoundryCellService/ ngrx path. Not in this slice's scope; would be a follow-up alongside the broader cells deep-dive.