Simplify Deployments tabs and fix duplicate Version button
Deployments page: - Remove redundant context chips (US East, Development, 24h) — topbar already shows these - Rename Timeline tab → Pipeline with appropriate icon - Remove Table tab (raw data table, low value vs Pipeline view) - Remove Correlations tab (deployment correlations belong in Pipeline view) - Keep only Pipeline + Approvals tabs Releases Versions tab: - Fix duplicate "New Version" button — ReleaseListComponent now accepts [embedded]="true" to suppress its pageAction when rendered inside the unified Releases page (which already has "New Release" page action) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Filter bar adoption: SPRINT_20260308_015_FE (FE-OFB-003)
|
||||
import { Component, OnInit, OnDestroy, inject, signal, computed } from '@angular/core';
|
||||
import { Component, Input, OnInit, OnDestroy, inject, signal, computed } from '@angular/core';
|
||||
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
||||
|
||||
import { PlatformContextStore } from '../../../../core/context/platform-context.store';
|
||||
@@ -758,6 +758,8 @@ import { PageActionOutletComponent } from '../../../../shared/components/page-ac
|
||||
`],
|
||||
})
|
||||
export class ReleaseListComponent implements OnInit, OnDestroy {
|
||||
/** When true, suppresses page action (used when embedded as a tab inside another page). */
|
||||
@Input() embedded = false;
|
||||
private readonly dateFmt = inject(DateFormatService);
|
||||
private readonly pageAction = inject(PageActionService);
|
||||
|
||||
@@ -831,7 +833,9 @@ export class ReleaseListComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
ngOnInit(): void {
|
||||
this.pageAction.set({ label: 'New Version', route: '/releases/versions/new' });
|
||||
if (!this.embedded) {
|
||||
this.pageAction.set({ label: 'New Version', route: '/releases/versions/new' });
|
||||
}
|
||||
this.context.initialize();
|
||||
this.route.queryParamMap.subscribe((params) => {
|
||||
this.applyingFromQuery = true;
|
||||
|
||||
@@ -18,9 +18,7 @@ import { ConfirmDialogComponent } from '../../shared/components/confirm-dialog/c
|
||||
import { ModalComponent } from '../../shared/components/modal/modal.component';
|
||||
|
||||
const VIEW_MODE_TABS: StellaPageTab[] = [
|
||||
{ id: 'timeline', label: 'Timeline', icon: 'M12 12m-10 0a10 10 0 1 0 20 0 10 10 0 1 0-20 0|||M12 6v6l4 2' },
|
||||
{ id: 'table', label: 'Table', icon: 'M8 6h13|||M8 12h13|||M8 18h13|||M3 6h.01|||M3 12h.01|||M3 18h.01' },
|
||||
{ id: 'correlations', label: 'Correlations', icon: 'M22 12h-4l-3 9L9 3l-3 9H2' },
|
||||
{ id: 'timeline', label: 'Pipeline', icon: 'M22 12h-4l-3 9L9 3l-3 9H2' },
|
||||
{ id: 'approvals', label: 'Approvals', icon: 'M9 11l3 3L22 4|||M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11' },
|
||||
];
|
||||
import { StellaPageTabsComponent, StellaPageTab } from '../../shared/components/stella-page-tabs/stella-page-tabs.component';
|
||||
@@ -72,12 +70,6 @@ function deriveOutcomeIcon(status: string): string {
|
||||
<p>Deployment runs, approvals, and promotion activity.</p>
|
||||
</header>
|
||||
|
||||
<div class="context">
|
||||
<span>{{ context.regionSummary() }}</span>
|
||||
<span>{{ context.environmentSummary() }}</span>
|
||||
<span>{{ context.timeWindow() }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Pending approvals inline lane (dashboard-style action cards) -->
|
||||
@if (pendingApprovals().length > 0 && viewMode() !== 'approvals') {
|
||||
<div class="pending-lane">
|
||||
@@ -304,60 +296,6 @@ function deriveOutcomeIcon(status: string): string {
|
||||
</app-timeline-list>
|
||||
</div>
|
||||
}
|
||||
@case ('correlations') {
|
||||
<div class="clusters">
|
||||
@for (cluster of correlationClusters(); track cluster.key) {
|
||||
<article>
|
||||
<h3>{{ cluster.key }}</h3>
|
||||
<p>{{ cluster.count }} events · {{ cluster.releases }} release version(s)</p>
|
||||
<p>{{ cluster.environments }}</p>
|
||||
</article>
|
||||
} @empty {
|
||||
<div class="banner">No run correlations match the current filters.</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@default {
|
||||
<table class="stella-table stella-table--striped stella-table--hoverable stella-table--bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Run</th>
|
||||
<th>Release Version</th>
|
||||
<th>Lane</th>
|
||||
<th>Outcome</th>
|
||||
<th>Environment</th>
|
||||
<th>Needs Approval</th>
|
||||
<th>Data Integrity</th>
|
||||
<th>When</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (row of pagedRows(); track row.activityId) {
|
||||
<tr>
|
||||
<td><a [routerLink]="['/releases/runs', row.releaseId, 'summary']">{{ row.activityId }}</a></td>
|
||||
<td>{{ row.releaseName }}</td>
|
||||
<td>{{ deriveLane(row) }}</td>
|
||||
<td>{{ deriveOutcome(row) }}</td>
|
||||
<td>{{ row.targetRegion || '-' }}/{{ row.targetEnvironment || '-' }}</td>
|
||||
<td>{{ deriveNeedsApproval(row) ? 'yes' : 'no' }}</td>
|
||||
<td>{{ deriveDataIntegrity(row) }}</td>
|
||||
<td>{{ formatDate(row.occurredAt) }}</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
<tr><td colspan="8">No runs match the active filters.</td></tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="display: flex; justify-content: flex-end; padding-top: 0.75rem;">
|
||||
<app-pagination
|
||||
[total]="filteredRows().length"
|
||||
[currentPage]="currentPage()"
|
||||
[pageSize]="pageSize()"
|
||||
[pageSizes]="[5, 10, 25, 50]"
|
||||
(pageChange)="onPageChange($event)"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -547,7 +485,7 @@ export class ReleasesActivityComponent implements OnInit, OnDestroy {
|
||||
readonly loading = signal(false);
|
||||
readonly error = signal<string | null>(null);
|
||||
readonly rows = signal<ReleaseActivityProjection[]>([]);
|
||||
readonly viewMode = signal<'timeline' | 'table' | 'correlations' | 'approvals'>('timeline');
|
||||
readonly viewMode = signal<'timeline' | 'approvals'>('timeline');
|
||||
|
||||
// ── Pending approvals card lane ──────────────────────────────────
|
||||
@ViewChild('apcScroll') apcScrollRef?: ElementRef<HTMLDivElement>;
|
||||
@@ -715,7 +653,7 @@ export class ReleasesActivityComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.route.queryParamMap.subscribe((params) => {
|
||||
const view = (params.get('view') ?? '').toLowerCase();
|
||||
if (view && (view === 'timeline' || view === 'table' || view === 'correlations' || view === 'approvals')) {
|
||||
if (view && (view === 'timeline' || view === 'approvals')) {
|
||||
if (this.viewMode() !== view) {
|
||||
this.viewMode.set(view);
|
||||
if (view === 'approvals') this.loadApprovals();
|
||||
@@ -792,7 +730,7 @@ export class ReleasesActivityComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
onTabChange(tab: string): void {
|
||||
this.viewMode.set(tab as 'timeline' | 'table' | 'correlations' | 'approvals');
|
||||
this.viewMode.set(tab as 'timeline' | 'approvals');
|
||||
if (tab === 'approvals') this.loadApprovals();
|
||||
this.applyFilters();
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ export interface PipelineRelease {
|
||||
} <!-- end pipeline tab -->
|
||||
|
||||
@if (activeTab() === 'versions') {
|
||||
<app-release-list />
|
||||
<app-release-list [embedded]="true" />
|
||||
}
|
||||
</div>
|
||||
`,
|
||||
|
||||
Reference in New Issue
Block a user