Web UI: feature updates across all modules
Broad UI improvements spanning auth, branding, notifications, agents, analytics, approvals, audit-log, bundles, configuration, console-admin, dashboard, deployments, doctor, environments, evidence, feed-mirror, graph, integration-hub, issuer-trust, lineage, notify, offline-kit, policy, promotions, quota, registry, release-orchestrator, releases, sbom, scans, secret-detection, security, settings, setup-wizard, system-health, topology, triage, trust-admin, unknowns, vex-hub, vulnerabilities, and watchlist features. Adds new shared components (page-action-outlet, stella-action-card, stella-form-field), scripts feature module, audit-trust component, e2e test helpers, and release page e2e specs. Updates auth session model, branding service, color tokens, form styles, and i18n translations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -112,6 +112,61 @@ Do NOT create custom `.stat-card`, `.summary-card`, `.kpi-card`, or `.posture-ca
|
||||
- If `route` is set: card is clickable with hover lift + arrow
|
||||
- If no `route`: static display, no hover effect
|
||||
|
||||
## Horizontal Scroll Card Lane Pattern (Reusable)
|
||||
|
||||
A reusable pattern for displaying actionable items as horizontally scrollable cards with
|
||||
gradient fades and scroll arrows. Used in the dashboard (environment cards, pending actions)
|
||||
and the approvals inbox (approval cards with inline actions).
|
||||
|
||||
### Architecture
|
||||
|
||||
Three layers:
|
||||
1. **Wrapper** (`*-lane-wrapper`) — relative-positioned container with `::before`/`::after` gradient pseudo-elements
|
||||
2. **Scroll container** (`*-lane`) — flex row with `overflow-x: auto`, hidden scrollbar, `scroll-behavior: smooth`
|
||||
3. **Cards** — fixed-width (`280px`) flex items with `flex-shrink: 0`
|
||||
|
||||
### Scroll arrow signals (TypeScript)
|
||||
|
||||
```typescript
|
||||
@ViewChild('myScroll') myScrollRef?: ElementRef<HTMLDivElement>;
|
||||
readonly showLeftArrow = signal(false);
|
||||
readonly showRightArrow = signal(false);
|
||||
|
||||
onScroll(): void { this.updateArrows(); }
|
||||
scrollCards(direction: 'left' | 'right'): void {
|
||||
this.myScrollRef?.nativeElement?.scrollBy({ left: direction === 'left' ? -300 : 300, behavior: 'smooth' });
|
||||
}
|
||||
private updateArrows(): void {
|
||||
const el = this.myScrollRef?.nativeElement;
|
||||
if (!el) { this.showLeftArrow.set(false); this.showRightArrow.set(false); return; }
|
||||
this.showLeftArrow.set(el.scrollLeft > 1);
|
||||
this.showRightArrow.set(el.scrollWidth - el.scrollLeft - el.clientWidth > 1);
|
||||
}
|
||||
```
|
||||
|
||||
### Gradient fades (CSS)
|
||||
|
||||
```scss
|
||||
.my-wrapper.can-scroll-left::before {
|
||||
content: ''; position: absolute; top: 0; left: 0; bottom: 0; width: 56px;
|
||||
background: linear-gradient(to right, var(--color-surface-primary) 0%, transparent 100%);
|
||||
pointer-events: none; z-index: 1;
|
||||
}
|
||||
.my-wrapper.can-scroll-right::after { /* mirror for right side */ }
|
||||
```
|
||||
|
||||
### Confirmation dialogs for card actions
|
||||
|
||||
- **Production approve**: `<app-confirm-dialog>` with `variant="warning"` and `ViewChild` ref, call `.open()` programmatically
|
||||
- **Reject with reason**: Custom inline dialog overlay with `<textarea [(ngModel)]>` for optional reason
|
||||
- **Detail popup**: `<app-modal size="lg">` — shows summary immediately, loads full detail via API on open
|
||||
|
||||
### Reference implementations
|
||||
|
||||
- Dashboard environment cards: `features/dashboard-v3/dashboard-v3.component.ts` (`.env-grid-wrapper`)
|
||||
- Approvals inbox cards: `features/approvals/approvals-inbox.component.ts` (`.cards-lane-wrapper`, `.apc` cards)
|
||||
- Stella Action Card List: `shared/components/stella-action-card/` (simpler variant without arrows)
|
||||
|
||||
## Tab Navigation Convention (MANDATORY)
|
||||
|
||||
All page-level tab navigation **must** use `<stella-page-tabs>`.
|
||||
@@ -271,6 +326,24 @@ Three filter component types:
|
||||
- Use `app-filter-bar` when search + multiple dropdowns + active chips are needed
|
||||
- Compact inline chips: 28px height, no border default, dropdown on click
|
||||
|
||||
**Filter container overflow (CRITICAL):**
|
||||
|
||||
Filter containers that hold `stella-filter-chip` or `stella-filter-multi` MUST use
|
||||
`overflow: visible` so dropdown panels are not clipped. Do NOT use `overflow-x: auto`
|
||||
or `overflow: hidden` on filter row containers — this clips the absolute-positioned
|
||||
dropdown panels (`z-index: 200`) below the fold.
|
||||
|
||||
```css
|
||||
/* CORRECT — dropdowns escape the container */
|
||||
.filters { display: flex; flex-wrap: wrap; overflow: visible; gap: 0.5rem; }
|
||||
|
||||
/* WRONG — clips dropdown panels */
|
||||
.filters { display: flex; flex-wrap: nowrap; overflow-x: auto; }
|
||||
```
|
||||
|
||||
The topbar header row uses `overflow: visible` for this reason — all page-level
|
||||
filter rows must follow the same pattern.
|
||||
|
||||
## Filter Convention (MANDATORY)
|
||||
|
||||
Three filter component types:
|
||||
|
||||
Reference in New Issue
Block a user