From 9d5f33e45027f516d5ce6cbc7e90f5b894c1aff9 Mon Sep 17 00:00:00 2001 From: master <> Date: Fri, 27 Mar 2026 16:20:02 +0200 Subject: [PATCH] Phase C: Merge Versions into Releases as a tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify the Releases page with Pipeline + Versions tabs: - Add stella-page-tabs with Pipeline (default) and Versions tabs - Pipeline tab shows the existing release pipeline table - Versions tab renders the ReleaseListComponent (version catalog) inline - /releases/versions redirects to /releases?tab=versions for bookmarks - Updated subtitle to "Versions, deployments, approvals, and promotion pipeline." The Versions sidebar item was already removed in Phase A. This completes the unification — one place for all release-related views. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../releases-unified-page.component.ts | 26 +++++++++++++++++-- .../src/app/routes/releases.routes.ts | 9 +++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/Web/StellaOps.Web/src/app/features/releases/releases-unified-page.component.ts b/src/Web/StellaOps.Web/src/app/features/releases/releases-unified-page.component.ts index 4a1dd79de..9d02a3587 100644 --- a/src/Web/StellaOps.Web/src/app/features/releases/releases-unified-page.component.ts +++ b/src/Web/StellaOps.Web/src/app/features/releases/releases-unified-page.component.ts @@ -12,14 +12,21 @@ import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, inject, signal, import { PageActionService } from '../../core/services/page-action.service'; import { PageActionOutletComponent } from '../../shared/components/page-action-outlet/page-action-outlet.component'; import { UpperCasePipe, SlicePipe } from '@angular/common'; -import { RouterLink } from '@angular/router'; +import { RouterLink, ActivatedRoute } from '@angular/router'; import { StellaFilterChipComponent, FilterChipOption } from '../../shared/components/stella-filter-chip/stella-filter-chip.component'; +import { StellaPageTabsComponent, StellaPageTab } from '../../shared/components/stella-page-tabs/stella-page-tabs.component'; import { PaginationComponent, PageChangeEvent } from '../../shared/components/pagination/pagination.component'; import { TableColumn } from '../../shared/components/data-table/data-table.component'; import { ReleaseManagementStore } from '../release-orchestrator/releases/release.store'; +import { ReleaseListComponent } from '../release-orchestrator/releases/release-list/release-list.component'; import { PlatformContextStore } from '../../core/context/platform-context.store'; import type { ReleaseWorkflowStatus } from '../../core/api/release-management.models'; +const RELEASE_TABS: readonly StellaPageTab[] = [ + { id: 'pipeline', label: 'Pipeline', icon: 'M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z' }, + { id: 'versions', label: 'Versions', icon: 'M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5' }, +]; + // ── Data model ────────────────────────────────────────────────────────────── export interface PipelineRelease { @@ -52,8 +59,10 @@ export interface PipelineRelease { SlicePipe, RouterLink, StellaFilterChipComponent, + StellaPageTabsComponent, PaginationComponent, PageActionOutletComponent, + ReleaseListComponent, ], changeDetection: ChangeDetectionStrategy.OnPush, template: ` @@ -61,11 +70,15 @@ export interface PipelineRelease {

Releases

-

Unified pipeline view — versions, deployments, hotfixes, and approvals.

+

Versions, deployments, approvals, and promotion pipeline.

+ + + @if (activeTab() === 'pipeline') {
} + } + + @if (activeTab() === 'versions') { + + }
`, styles: [` @@ -361,6 +379,10 @@ export class ReleasesUnifiedPageComponent implements OnInit, OnDestroy { private readonly pageAction = inject(PageActionService); private readonly store = inject(ReleaseManagementStore); private readonly context = inject(PlatformContextStore); + private readonly route = inject(ActivatedRoute); + + readonly releaseTabs = RELEASE_TABS; + readonly activeTab = signal(this.route.snapshot.queryParamMap.get('tab') || 'pipeline'); ngOnInit(): void { this.pageAction.set({ label: 'New Release', route: '/releases/new' }); diff --git a/src/Web/StellaOps.Web/src/app/routes/releases.routes.ts b/src/Web/StellaOps.Web/src/app/routes/releases.routes.ts index 84ace2b03..87542317a 100644 --- a/src/Web/StellaOps.Web/src/app/routes/releases.routes.ts +++ b/src/Web/StellaOps.Web/src/app/routes/releases.routes.ts @@ -76,14 +76,11 @@ export const RELEASES_ROUTES: Routes = [ (m) => m.ReleaseDetailPageComponent, ), }, + // Versions merged into Releases as a tab — redirect for bookmarks { path: 'versions', - title: 'Release Versions', - data: { breadcrumb: 'Release Versions', semanticObject: 'version' }, - loadComponent: () => - import('../features/release-orchestrator/releases/release-list/release-list.component').then( - (m) => m.ReleaseListComponent, - ), + redirectTo: '/releases?tab=versions', + pathMatch: 'full' as const, }, { path: 'new',