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],
|
imports: [RouterModule, StellaFilterChipComponent, PaginationComponent, PageActionOutletComponent],
|
||||||
template: `
|
template: `
|
||||||
<div class="release-list">
|
<div class="release-list">
|
||||||
<header class="list-header">
|
@if (!embedded) {
|
||||||
<div class="list-header__title">
|
<header class="list-header">
|
||||||
<h1>Release Versions</h1>
|
<div class="list-header__title">
|
||||||
<p class="subtitle">Digest-first release version catalog across standard and hotfix lanes</p>
|
<h1>Release Versions</h1>
|
||||||
</div>
|
<p class="subtitle">Digest-first release version catalog across standard and hotfix lanes</p>
|
||||||
<app-page-action-outlet />
|
</div>
|
||||||
</header>
|
<app-page-action-outlet />
|
||||||
|
</header>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<div class="filter-search">
|
<div class="filter-search">
|
||||||
|
|||||||
@@ -173,7 +173,14 @@ function deriveOutcomeIcon(status: string): string {
|
|||||||
|
|
||||||
@if (viewMode() === 'approvals') {
|
@if (viewMode() === 'approvals') {
|
||||||
<!-- Approvals tab content -->
|
<!-- 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) {
|
@for (toggle of gateToggles; track toggle.id) {
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="gate-toggle"
|
class="gate-toggle"
|
||||||
@@ -514,18 +521,33 @@ export class ReleasesActivityComponent implements OnInit, OnDestroy {
|
|||||||
{ id: 'security', label: 'Security' },
|
{ id: 'security', label: 'Security' },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
readonly approvalSearchQuery = signal('');
|
||||||
|
|
||||||
readonly gateToggleState = signal<Record<string, boolean>>({
|
readonly gateToggleState = signal<Record<string, boolean>>({
|
||||||
gated: true,
|
gated: false,
|
||||||
policy: false,
|
policy: false,
|
||||||
ops: false,
|
ops: false,
|
||||||
security: false,
|
security: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
readonly filteredApprovals = computed(() => {
|
readonly filteredApprovals = computed(() => {
|
||||||
|
let result = this.allApprovals();
|
||||||
const toggles = this.gateToggleState();
|
const toggles = this.gateToggleState();
|
||||||
const activeGates = Object.entries(toggles).filter(([, v]) => v).map(([k]) => k);
|
const activeGates = Object.entries(toggles).filter(([, v]) => v).map(([k]) => k);
|
||||||
if (activeGates.length === 0) return this.allApprovals();
|
if (activeGates.length > 0) {
|
||||||
return this.allApprovals().filter((apr) => activeGates.includes(this.deriveGateType(apr)));
|
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)
|
// Lane filter reads from global context (header toggle)
|
||||||
|
|||||||
Reference in New Issue
Block a user