Phase C: Merge Versions into Releases as a tab
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) <noreply@anthropic.com>
This commit is contained in:
@@ -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 {
|
||||
<header class="rup__header">
|
||||
<div>
|
||||
<h1 class="rup__title">Releases</h1>
|
||||
<p class="rup__subtitle">Unified pipeline view — versions, deployments, hotfixes, and approvals.</p>
|
||||
<p class="rup__subtitle">Versions, deployments, approvals, and promotion pipeline.</p>
|
||||
</div>
|
||||
<app-page-action-outlet />
|
||||
</header>
|
||||
|
||||
<stella-page-tabs [tabs]="releaseTabs" [activeTab]="activeTab()" urlParam="tab"
|
||||
(tabChange)="activeTab.set($event)" ariaLabel="Releases tabs" />
|
||||
|
||||
@if (activeTab() === 'pipeline') {
|
||||
<!-- Pipeline -->
|
||||
<div class="rup__filters">
|
||||
<div class="rup__search">
|
||||
@@ -242,6 +255,11 @@ export interface PipelineRelease {
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
} <!-- end pipeline tab -->
|
||||
|
||||
@if (activeTab() === 'versions') {
|
||||
<app-release-list />
|
||||
}
|
||||
</div>
|
||||
`,
|
||||
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<string>(this.route.snapshot.queryParamMap.get('tab') || 'pipeline');
|
||||
|
||||
ngOnInit(): void {
|
||||
this.pageAction.set({ label: 'New Release', route: '/releases/new' });
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user