From e4779a430fea066ba068e0bc7d2d49a50a6d8cff Mon Sep 17 00:00:00 2001 From: master <> Date: Sun, 8 Mar 2026 11:54:57 +0200 Subject: [PATCH] feat(ui): ship release promotions cutover --- ...60308_010_FE_release_promotions_cutover.md | 96 ++++++ .../web/release-promotions-cutover-ui.md | 22 ++ docs/modules/ui/README.md | 3 + docs/modules/ui/TASKS.md | 4 + .../RESTORATION_PRIORITIES.md | 4 + docs/modules/ui/implementation_plan.md | 2 + .../ui/release-promotions-cutover/README.md | 51 ++++ src/Web/StellaOps.Web/src/app/app.routes.ts | 9 +- .../promotions/create-promotion.component.ts | 111 ++++++- .../features/promotions/promotions.routes.ts | 2 +- .../release-detail.component.ts | 18 +- .../release-ops-overview-page.component.ts | 2 +- .../app-sidebar/app-sidebar.component.ts | 13 +- .../app-sidebar/sidebar-preference.service.ts | 2 +- .../src/app/routes/releases.routes.ts | 52 +++- .../release-detail.live-refresh.spec.ts | 64 ++++ .../release-promotions-cutover.spec.ts | 196 +++++++++++++ .../e2e/release-promotions-cutover.spec.ts | 276 ++++++++++++++++++ 18 files changed, 912 insertions(+), 15 deletions(-) create mode 100644 docs-archived/implplan/SPRINT_20260308_010_FE_release_promotions_cutover.md create mode 100644 docs/features/checked/web/release-promotions-cutover-ui.md create mode 100644 docs/modules/ui/release-promotions-cutover/README.md create mode 100644 src/Web/StellaOps.Web/src/tests/releases/release-promotions-cutover.spec.ts create mode 100644 src/Web/StellaOps.Web/tests/e2e/release-promotions-cutover.spec.ts diff --git a/docs-archived/implplan/SPRINT_20260308_010_FE_release_promotions_cutover.md b/docs-archived/implplan/SPRINT_20260308_010_FE_release_promotions_cutover.md new file mode 100644 index 000000000..9acd9a0fc --- /dev/null +++ b/docs-archived/implplan/SPRINT_20260308_010_FE_release_promotions_cutover.md @@ -0,0 +1,96 @@ +# Sprint 20260308_010_FE - Release Promotions Cutover + +## Topic & Scope +- Restore the dormant promotions workflow as a first-class `Releases` capability instead of leaving it split between orphaned components, queue aliases, and approval-only entry points. +- Make `/releases/promotions` the canonical owner route for promotion list, creation, and detail flows, with legacy `/release-control/promotions*` and `/releases/promotion-queue*` bookmarks preserved. +- Wire a real release-context handoff from the active release workbench into the promotion wizard so operators can start a usable promotion request from a release they are reviewing. +- Working directory: `src/Web/StellaOps.Web`. +- Expected evidence: focused Angular route/component tests, Playwright route and workflow verification, updated UI docs, archived sprint. + +## Dependencies & Concurrency +- Builds on the shipped IA and canonical route work already completed for `Releases`, Decisioning Studio, and contextual return-to flows. +- Safe to implement in parallel with unrelated Router or live-search work as long as edits stay within `src/Web/StellaOps.Web` and scoped UI docs. + +## Documentation Prerequisites +- `docs/modules/ui/README.md` +- `docs/modules/ui/implementation_plan.md` +- `docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md` +- `docs/modules/ui/policy-decisioning-studio/README.md` + +## Delivery Tracker + +### FE-RP-001 - Canonical promotions owner route and alias cutover +Status: DONE +Dependency: none +Owners: Developer / Implementer +Task description: +- Mount the existing promotions list, create, and detail workflow under the live `Releases` route tree as `/releases/promotions`. +- Repair stale legacy redirects so `/release-control/promotions*` and `/releases/promotion-queue*` land on the canonical promotions subtree without dropping query state. +- Surface the canonical path from live release navigation so the workflow is discoverable from the active shell. + +Completion criteria: +- [x] `routes/releases.routes.ts` mounts a canonical promotions subtree. +- [x] Legacy aliases redirect to the canonical subtree while preserving query params and fragments. +- [x] Live shell navigation points at `/releases/promotions`, not the stale queue alias. + +### FE-RP-002 - Release-context promotion request handoff +Status: DONE +Dependency: FE-RP-001 +Owners: Developer / Implementer +Task description: +- Complete the promotion request handoff from the active release workbench so the operator can leave a release or run context and enter the promotion wizard with prefilled identity and a deterministic return path. +- Merge the worthwhile behavior from the dropped promotion-request surface, especially decisioning preview handoff and contextual return-to routing, into the canonical promotion wizard instead of reviving a second product page. + +Completion criteria: +- [x] Active release workbench actions navigate into the canonical promotion wizard with release context. +- [x] The promotion wizard preloads release context and offers a Decisioning Studio deep link with a valid return-to contract. +- [x] Operator back-navigation and post-submit behavior remain usable and deterministic. + +### FE-RP-003 - Verification coverage for route cutover and usable workflow +Status: DONE +Dependency: FE-RP-002 +Owners: Developer / Implementer, Test Automation, QA +Task description: +- Add focused Angular tests for the canonical route tree, release-context handoff, and promotion wizard state hydration. +- Add Playwright coverage that proves legacy promotion aliases cut over correctly and that a real operator can reach the promotion wizard from the live Releases area. + +Completion criteria: +- [x] Targeted Angular tests cover the canonical promotions route contract and release-context handoff. +- [x] Playwright covers at least one live shell entry point plus one legacy alias. +- [x] The scoped test suite passes deterministically. + +### FE-RP-004 - Docs sync, archive, and shipped-feature note +Status: DONE +Dependency: FE-RP-003 +Owners: Developer / Implementer, Documentation author +Task description: +- Document the canonical promotions owner route, alias policy, and release-context handoff in the UI module docs. +- Record the tested behavior in a checked feature note, update the task board and implementation plan, then archive the sprint only after all delivery tasks are actually complete. + +Completion criteria: +- [x] Module docs describe the canonical promotions workflow and alias contract. +- [x] Checked-feature verification note records the actual commands and outcomes. +- [x] Sprint is archived with all tasks marked `DONE`. + +## Execution Log +| Date (UTC) | Update | Owner | +| --- | --- | --- | +| 2026-03-08 | Sprint created and moved to DOING for canonical release promotions cutover. | Implementer | +| 2026-03-08 | Mounted canonical `/releases/promotions` routes, repaired `/release-control/promotions*` and `/releases/promotion-queue*` aliases, and split shell surfacing into distinct `Approvals` and `Promotions` entries. | Implementer | +| 2026-03-08 | Wired release-context handoff from the active release workbench into the canonical promotion wizard and merged decisioning-preview behavior from the dropped promotion-request surface. | Implementer | +| 2026-03-08 | Verification passed: Angular targeted tests `2` files / `8` tests, Playwright `2` scenarios, and `npm run build` with existing bundle-budget warnings only. | Implementer | + +## Decisions & Risks +- The sprint restores one operator workflow, not the full legacy release-orchestrator shell. If deeper release dashboards or environment editors prove valuable later, they need their own bounded sprint. +- Promotion creation stays under `Releases`, while approval adjudication remains under `Releases > Approvals`; the UI must avoid collapsing those two surfaces back into one ambiguous queue. +- Route alias handling must preserve query params and fragments so release-context and bookmark flows remain deterministic. +- Browser verification initially exposed a live-shell compile blocker in `src/Web/StellaOps.Web/src/app/layout/app-sidebar/sidebar-preference.service.ts`; the sidebar preference contract was repaired as part of this sprint because the releases shell could not boot otherwise. +- Verification commands: + - `npm run test -- --watch=false --include src/tests/releases/release-promotions-cutover.spec.ts --include src/tests/releases/release-detail.live-refresh.spec.ts` + - `npx playwright test --config playwright.config.ts tests/e2e/release-promotions-cutover.spec.ts --workers=1` + - `npm run build` + +## Next Checkpoints +- Route and navigation cutover complete with local tests. +- Release-context promotion handoff verified in browser. +- Sprint archived and committed locally without unrelated files. diff --git a/docs/features/checked/web/release-promotions-cutover-ui.md b/docs/features/checked/web/release-promotions-cutover-ui.md new file mode 100644 index 000000000..fe9453aca --- /dev/null +++ b/docs/features/checked/web/release-promotions-cutover-ui.md @@ -0,0 +1,22 @@ +# Release Promotions Cutover UI + +## Verified Scope +- Canonical `Releases` ownership for promotions list, create, and detail routes under `/releases/promotions`. +- Legacy `/release-control/promotions*` and `/releases/promotion-queue*` bookmarks redirect to the canonical promotions subtree with query-state preservation. +- Active release workbench handoff into the canonical promotion wizard with `releaseId` and `returnTo`. +- Promotion wizard release-context hydration, Decisioning Studio handoff, and successful submission into promotion detail. + +## Verification Commands +- `npm run test -- --watch=false --include src/tests/releases/release-promotions-cutover.spec.ts --include src/tests/releases/release-detail.live-refresh.spec.ts` +- `npx playwright test --config playwright.config.ts tests/e2e/release-promotions-cutover.spec.ts --workers=1` +- `npm run build` + +## Verification Results +- Angular: `2` files passed, `8` tests passed. +- Playwright: `2` scenarios passed. +- Build: passed. +- Build warnings: existing bundle-budget warnings only for the initial bundle and existing setup-wizard component stylesheet budgets. + +## Notes +- Browser verification initially exposed a live-shell compile error in `sidebar-preference.service.ts`; the service contract was repaired so the shell can boot and the promotions flow can be exercised in-browser. +- Verified on UTC: `2026-03-08T09:45:51.0108656Z` diff --git a/docs/modules/ui/README.md b/docs/modules/ui/README.md index e7ec22be2..f9409ba3a 100644 --- a/docs/modules/ui/README.md +++ b/docs/modules/ui/README.md @@ -9,6 +9,8 @@ The Console presents operator dashboards for scans, policies, VEX evidence, runtime posture, and admin workflows. ## Latest updates (2026-03-08) +- Shipped the canonical `Releases > Promotions` cutover, including repaired `/release-control/promotions*` and `/releases/promotion-queue*` aliases, release-context promotion wizard handoff, and a usable create-to-detail flow. +- Added checked-feature verification for release promotions at `../../features/checked/web/release-promotions-cutover-ui.md`. - Preserved canonical `Ops > Platform Setup` leaf URLs so `regions-environments`, `promotion-paths`, `workflows-gates`, and `gate-profiles` no longer rewrite into `Setup > Topology` on direct entry or quick-link navigation. - Added checked-feature verification for canonical platform-setup route preservation at `../../features/checked/web/platform-setup-canonical-route-preservation-ui.md`. - Shipped the `Mission Control`, `Security`, and `Ops > Operations` security-leaves cutover, including canonical surfacing for alerts, activity, unknowns, and notifications plus repaired `/analyze/unknowns*` and `/notify` ownership. @@ -89,6 +91,7 @@ The Console presents operator dashboards for scans, policies, VEX evidence, runt - ./topology-trust-administration/README.md - ./security-operations-leaves/README.md - ./platform-setup-canonical-route-preservation/README.md +- ./release-promotions-cutover/README.md - ./triage-explainability-workspace/README.md - ./workflow-visualization-replay/README.md - ./contextual-actions-patterns/README.md diff --git a/docs/modules/ui/TASKS.md b/docs/modules/ui/TASKS.md index 08954125d..c36deba12 100644 --- a/docs/modules/ui/TASKS.md +++ b/docs/modules/ui/TASKS.md @@ -111,6 +111,10 @@ - [DONE] FE-PLATFORMSETUP-001 Reproduce and bound the canonical rewrite defect - [DONE] FE-PLATFORMSETUP-002 Preserve canonical platform-setup URLs in the Web router - [DONE] FE-PLATFORMSETUP-003 Add focused regression coverage and retest +- [DONE] FE-RP-001 Mount canonical `/releases/promotions` routes and preserve legacy promotion aliases +- [DONE] FE-RP-002 Wire release-context handoff into the canonical promotion wizard +- [DONE] FE-RP-003 Verify route cutover and usable promotion request workflow +- [DONE] FE-RP-004 Sync docs, archive the sprint, and record the shipped feature - [DONE] FE-PO-001 Freeze Operations overview taxonomy and submenu structure - [DONE] FE-PO-002 Overview page regrouping and blocking-card contract - [DONE] FE-PO-003 Legacy widget absorption matrix for Platform Ops diff --git a/docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md b/docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md index 590b3baca..17a416c6d 100644 --- a/docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md +++ b/docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md @@ -191,6 +191,10 @@ These branches probably contain valuable pieces, but the right home needs one mo - The issue is duplication between older release-orchestrator shells and the newer releases/evidence/setup IA. - Likely target: - `/releases`, `/evidence`, `/setup/topology`, and Decisioning Studio release-context entry points +- Notes: + - Shipped slice: `docs/modules/ui/release-promotions-cutover/README.md` + - Verified UI flow: `docs/features/checked/web/release-promotions-cutover-ui.md` + - Remaining review should focus on whether legacy release dashboards, environment editors, and evidence shells still add unique value beyond the active Releases and Evidence surfaces. ### 14. Evidence And Proof Exploration - Type: `merge` diff --git a/docs/modules/ui/implementation_plan.md b/docs/modules/ui/implementation_plan.md index 840de0c63..c1146f7d0 100644 --- a/docs/modules/ui/implementation_plan.md +++ b/docs/modules/ui/implementation_plan.md @@ -34,6 +34,7 @@ Provide a living plan for UI deliverables, dependencies, and evidence. - `docs/features/checked/web/topology-trust-administration-ui.md` - shipped verification note for canonical topology and trust setup shells, repaired settings/admin/platform aliases, and platform-setup handoffs. - `docs/features/checked/web/security-operations-leaves-ui.md` - shipped verification note for mission alerts/activity surfacing, unknowns route repair, notifications ownership, and legacy security alias cutover. - `docs/features/checked/web/platform-setup-canonical-route-preservation-ui.md` - shipped verification note for preserved `/ops/platform-setup/*` URLs during the shared setup/topology cutover. +- `docs/features/checked/web/release-promotions-cutover-ui.md` - shipped verification note for canonical release promotions routing, alias cutover, release-context wizard handoff, and end-to-end request submission. - `docs/modules/ui/reachability-witnessing/README.md` - detailed witness and proof UX dossier plus cross-shell deep-link contract. - `docs/modules/ui/platform-ops-consolidation/README.md` - detailed Operations overview taxonomy and legacy absorption plan. - `docs/modules/ui/offline-operations/README.md` - detailed owner-shell contract for Offline Kit, Feeds & Airgap, Evidence handoffs, and stale alias policy. @@ -42,6 +43,7 @@ Provide a living plan for UI deliverables, dependencies, and evidence. - `docs/modules/ui/topology-trust-administration/README.md` - canonical setup owner contract for topology inventory, trust administration, legacy trust redirects, and platform-setup handoffs. - `docs/modules/ui/security-operations-leaves/README.md` - canonical owner contract for mission alerts/activity, security unknowns, notifications, and stale `/analyze`/`/notify` handoffs. - `docs/modules/ui/platform-setup-canonical-route-preservation/README.md` - preserved route contract for canonical `/ops/platform-setup/*` leaves during the shared setup/topology cutover. +- `docs/modules/ui/release-promotions-cutover/README.md` - canonical promotions owner contract, alias rules, and release-context handoff for the Releases shell. - `docs/modules/ui/triage-explainability-workspace/README.md` - detailed artifact workspace and audit-bundle UX dossier. - `docs/modules/ui/workflow-visualization-replay/README.md` - detailed run-detail graph, timeline, replay, and evidence UX dossier. - `docs/modules/ui/contextual-actions-patterns/README.md` - shared placement contract for stray actions, pages, drawers, and tabs. diff --git a/docs/modules/ui/release-promotions-cutover/README.md b/docs/modules/ui/release-promotions-cutover/README.md new file mode 100644 index 000000000..1e28c1bfd --- /dev/null +++ b/docs/modules/ui/release-promotions-cutover/README.md @@ -0,0 +1,51 @@ +# Release Promotions Cutover + +## Purpose +- Make `Releases` own the promotion workflow instead of splitting it across stale queue aliases, orphaned promotion routes, and approval-only entry points. +- Keep approvals as the adjudication surface, but move promotion list, create, and detail flows under one canonical subtree. + +## Canonical Routes +- `/releases/promotions` +- `/releases/promotions/create` +- `/releases/promotions/:promotionId` + +## Alias Policy +- Preserve legacy `/release-control/promotions`, `/release-control/promotions/create`, and `/release-control/promotions/:promotionId` bookmarks. +- Preserve stale `/releases/promotion-queue`, `/releases/promotion-queue/create`, and `/releases/promotion-queue/:promotionId` bookmarks. +- Redirect aliases into the canonical `/releases/promotions*` subtree while preserving query params and fragments. + +## Shell Surfacing +- `Releases` sidebar now exposes separate `Approvals` and `Promotions` entries. +- `Releases > Overview` links to canonical `Promotions`. +- The active release workbench launches the promotion wizard directly instead of trapping the operator in a non-executable promote tab. + +## Release-Context Handoff +- The release workbench opens `/releases/promotions/create` with: + - `releaseId` + - `returnTo` +- The promotion wizard treats this as a first-class release-context launch: + - preloads environments for the supplied release + - advances directly to target selection once release identity is known + - keeps a return path back to the originating release or run context + - deep-links into Decisioning Studio with a return path back to the canonical promotion wizard + +## Merge Notes From Dropped Surfaces +- The dormant `PromotionRequestComponent` was not revived as a second page. +- Its worthwhile behavior was merged into the canonical wizard: + - contextual return-to handling + - decisioning preview handoff + - release-context launch semantics + +## Verification +- Angular tests cover: + - canonical promotions route ownership + - legacy alias redirects + - promotion wizard release-context hydration + - release workbench handoff into the canonical wizard +- Playwright covers: + - overview surfacing of the canonical promotions page + - legacy create alias redirect plus end-to-end promotion request submission + +## Related +- `docs/features/checked/web/release-promotions-cutover-ui.md` +- `docs/modules/ui/component-preservation-map/RESTORATION_PRIORITIES.md` diff --git a/src/Web/StellaOps.Web/src/app/app.routes.ts b/src/Web/StellaOps.Web/src/app/app.routes.ts index da507c6b9..699c95088 100644 --- a/src/Web/StellaOps.Web/src/app/app.routes.ts +++ b/src/Web/StellaOps.Web/src/app/app.routes.ts @@ -316,8 +316,13 @@ export const routes: Routes = [ { path: 'runs', redirectTo: '/releases/runs', pathMatch: 'full' }, { path: 'bundles', redirectTo: '/releases/bundles', pathMatch: 'full' }, { path: 'bundles/create', redirectTo: '/releases/bundles/create', pathMatch: 'full' }, - { path: 'promotions', redirectTo: '/releases/approvals', pathMatch: 'full' }, - { path: 'promotions/create', redirectTo: '/releases/approvals', pathMatch: 'full' }, + { path: 'promotions', redirectTo: preserveAppRedirect('/releases/promotions'), pathMatch: 'full' }, + { path: 'promotions/create', redirectTo: preserveAppRedirect('/releases/promotions/create'), pathMatch: 'full' }, + { + path: 'promotions/:promotionId', + redirectTo: preserveAppRedirect('/releases/promotions/:promotionId'), + pathMatch: 'full', + }, { path: 'environments', redirectTo: '/releases/environments', pathMatch: 'full' }, { path: 'regions', redirectTo: '/releases/environments', pathMatch: 'full' }, { path: 'setup', redirectTo: '/ops/platform-setup', pathMatch: 'full' }, diff --git a/src/Web/StellaOps.Web/src/app/features/promotions/create-promotion.component.ts b/src/Web/StellaOps.Web/src/app/features/promotions/create-promotion.component.ts index 7427afd2f..f3cde491e 100644 --- a/src/Web/StellaOps.Web/src/app/features/promotions/create-promotion.component.ts +++ b/src/Web/StellaOps.Web/src/app/features/promotions/create-promotion.component.ts @@ -3,6 +3,7 @@ import { Component, computed, inject, + OnInit, signal, } from '@angular/core'; import { CommonModule } from '@angular/common'; @@ -16,6 +17,7 @@ import type { PromotionPreview, TargetEnvironment, } from '../../core/api/approval.models'; +import { buildContextReturnTo } from '../../shared/ui/context-route-state/context-route-state'; type Step = 1 | 2 | 3 | 4 | 5 | 6; @@ -27,7 +29,9 @@ type Step = 1 | 2 | 3 | 4 | 5 | 6; template: `
{{ releaseId() }}.
+