Fix approvals table actions, add search, and hide duplicate Versions header
Approvals tab: - Default gate toggles all OFF (shows all approvals, not just "gated" type) - Add search input field that filters by release name, version, environment, requestedBy, and status - Approve/Reject buttons now visible for all pending approvals (gate filter was hiding them by defaulting to only "gated" type) Versions tab: - Hide the ReleaseListComponent's own header (title + page-action-outlet) when embedded=true, eliminating the duplicate "New Version" button - Parent Release Control page already provides the header and dynamic button Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,13 +24,15 @@ import { PageActionOutletComponent } from '../../../../shared/components/page-ac
|
||||
imports: [RouterModule, StellaFilterChipComponent, PaginationComponent, PageActionOutletComponent],
|
||||
template: `
|
||||
<div class="release-list">
|
||||
<header class="list-header">
|
||||
<div class="list-header__title">
|
||||
<h1>Release Versions</h1>
|
||||
<p class="subtitle">Digest-first release version catalog across standard and hotfix lanes</p>
|
||||
</div>
|
||||
<app-page-action-outlet />
|
||||
</header>
|
||||
@if (!embedded) {
|
||||
<header class="list-header">
|
||||
<div class="list-header__title">
|
||||
<h1>Release Versions</h1>
|
||||
<p class="subtitle">Digest-first release version catalog across standard and hotfix lanes</p>
|
||||
</div>
|
||||
<app-page-action-outlet />
|
||||
</header>
|
||||
}
|
||||
|
||||
<div class="filters">
|
||||
<div class="filter-search">
|
||||
|
||||
@@ -173,7 +173,14 @@ function deriveOutcomeIcon(status: string): string {
|
||||
|
||||
@if (viewMode() === 'approvals') {
|
||||
<!-- Approvals tab content -->
|
||||
<div class="approvals-gate-toggles">
|
||||
<div class="activity-filters">
|
||||
<div class="filter-search">
|
||||
<svg class="filter-search__icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.3-4.3"></path>
|
||||
</svg>
|
||||
<input type="text" class="filter-search__input" placeholder="Search approvals..."
|
||||
[value]="approvalSearchQuery()" (input)="approvalSearchQuery.set($any($event.target).value)" />
|
||||
</div>
|
||||
@for (toggle of gateToggles; track toggle.id) {
|
||||
<button type="button"
|
||||
class="gate-toggle"
|
||||
@@ -514,18 +521,33 @@ export class ReleasesActivityComponent implements OnInit, OnDestroy {
|
||||
{ id: 'security', label: 'Security' },
|
||||
] as const;
|
||||
|
||||
readonly approvalSearchQuery = signal('');
|
||||
|
||||
readonly gateToggleState = signal<Record<string, boolean>>({
|
||||
gated: true,
|
||||
gated: false,
|
||||
policy: false,
|
||||
ops: false,
|
||||
security: false,
|
||||
});
|
||||
|
||||
readonly filteredApprovals = computed(() => {
|
||||
let result = this.allApprovals();
|
||||
const toggles = this.gateToggleState();
|
||||
const activeGates = Object.entries(toggles).filter(([, v]) => v).map(([k]) => k);
|
||||
if (activeGates.length === 0) return this.allApprovals();
|
||||
return this.allApprovals().filter((apr) => activeGates.includes(this.deriveGateType(apr)));
|
||||
if (activeGates.length > 0) {
|
||||
result = result.filter((apr) => activeGates.includes(this.deriveGateType(apr)));
|
||||
}
|
||||
const q = this.approvalSearchQuery().toLowerCase().trim();
|
||||
if (q) {
|
||||
result = result.filter((apr) =>
|
||||
apr.releaseName.toLowerCase().includes(q) ||
|
||||
apr.releaseVersion.toLowerCase().includes(q) ||
|
||||
apr.targetEnvironment.toLowerCase().includes(q) ||
|
||||
apr.requestedBy.toLowerCase().includes(q) ||
|
||||
apr.status.toLowerCase().includes(q)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
// Lane filter reads from global context (header toggle)
|
||||
|
||||
Reference in New Issue
Block a user