Remove redundant h2 titles from governance tab panels

Each governance sub-component had its own h2 title + subtitle that
duplicated the tab label and the parent "Policy Governance" context.
Removed the redundant headers from 13 tab components while preserving
action buttons (Configure Budget, Add Weight, New Profile, etc.) as
standalone right-aligned action bars.

Detail sub-routes (risk-profile-editor, conflict-resolution-wizard)
keep their titles since they are not tab panels.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-03-28 11:23:58 +02:00
parent 6c07b0b374
commit 17a01df611
13 changed files with 36 additions and 362 deletions

View File

@@ -29,13 +29,6 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="audit" [attr.aria-busy]="loading()">
<header class="audit__header">
<div>
<h2 class="audit__title">Audit Log</h2>
<p class="audit__subtitle">Track all governance configuration changes.</p>
</div>
</header>
<!-- Filters -->
<div class="filters">
<stella-filter-chip
@@ -236,23 +229,6 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
padding: 1.5rem;
}
.audit__header {
margin-bottom: 1.5rem;
}
.audit__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.audit__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
/* Filters */
.filters {
display: flex;

View File

@@ -28,18 +28,12 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="preview" [attr.aria-busy]="loading()">
<header class="preview__header">
<div>
<h2 class="preview__title">Impact Preview</h2>
<p class="preview__subtitle">Review the projected impact of your proposed changes before applying.</p>
</div>
<div class="preview__actions">
<div class="preview__actions">
<a routerLink="../trust-weights" class="btn btn--ghost">Cancel</a>
<button class="btn btn--primary" (click)="applyChanges()" [disabled]="applying()">
{{ applying() ? 'Applying...' : 'Apply Changes' }}
</button>
</div>
</header>
@if (impact(); as i) {
<!-- Impact Summary -->
@@ -208,30 +202,11 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
padding: 1.5rem;
}
.preview__header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
gap: 1rem;
}
.preview__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.preview__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.preview__actions {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
margin-bottom: 1rem;
}
.btn {

View File

@@ -31,18 +31,14 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="conflicts" [attr.aria-busy]="loading()">
<header class="conflicts__header">
<div>
<h2 class="conflicts__title">Policy Conflicts</h2>
<p class="conflicts__subtitle">Identify and resolve rule overlaps and precedence issues.</p>
</div>
<div class="conflicts__actions">
<button class="btn btn--secondary" (click)="runAnalysis()" [disabled]="analyzing()">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="16" height="16">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" />
</svg>
{{ analyzing() ? 'Analyzing...' : 'Run Analysis' }}
</button>
</header>
</div>
@if (dashboard(); as d) {
<!-- Summary Cards -->
@@ -254,24 +250,11 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
padding: 1.5rem;
}
.conflicts__header {
.conflicts__actions {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
}
.conflicts__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.conflicts__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
justify-content: flex-end;
gap: 0.5rem;
margin-bottom: 1rem;
}
.btn {

View File

@@ -24,13 +24,6 @@ import {
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="validator">
<header class="validator__header">
<div>
<h2 class="validator__title">Policy Validator</h2>
<p class="validator__subtitle">Validate policy documents against the schema.</p>
</div>
</header>
<div class="validator__content">
<div class="editor-section">
<div class="editor-section__header">
@@ -172,23 +165,6 @@ import {
flex-direction: column;
}
.validator__header {
margin-bottom: 1.5rem;
}
.validator__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.validator__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.validator__content {
display: grid;
grid-template-columns: 1fr 1fr;

View File

@@ -34,18 +34,12 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="config" [attr.aria-busy]="loading()">
<header class="config__header">
<div>
<h2 class="config__title">Budget Configuration</h2>
<p class="config__subtitle">Configure risk budget limits, thresholds, and enforcement policies.</p>
</div>
<div class="config__actions">
<div class="config__actions">
<a routerLink="../" class="btn btn--ghost">Cancel</a>
<button class="btn btn--primary" (click)="onSave()" [disabled]="!form.valid || saving()">
{{ saving() ? 'Saving...' : 'Save Changes' }}
</button>
</div>
</header>
@if (loadError()) {
<div class="error-state" role="alert">{{ loadError() }}</div>
@@ -233,29 +227,11 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
padding: 1.5rem;
}
.config__header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
}
.config__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.config__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.config__actions {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
margin-bottom: 1rem;
}
.error-state {

View File

@@ -28,15 +28,9 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="dashboard" [attr.aria-busy]="loading()">
<header class="dashboard__header">
<div>
<h2 class="dashboard__title">Risk Budget Overview</h2>
<p class="dashboard__subtitle">Monitor budget consumption and manage risk thresholds.</p>
</div>
<div class="dashboard__actions">
<div class="dashboard__actions">
<a routerLink="../budget/config" class="btn btn--secondary">Configure Budget</a>
</div>
</header>
@if (loadError()) {
<div class="error-state" role="alert">{{ loadError() }}</div>
@@ -196,24 +190,11 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
padding: 1.5rem;
}
.dashboard__header {
.dashboard__actions {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
}
.dashboard__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.dashboard__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
justify-content: flex-end;
gap: 0.5rem;
margin-bottom: 1rem;
}
.error-state {

View File

@@ -29,12 +29,7 @@ import { StellaFilterChipComponent } from '../../shared/components/stella-filter
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="profiles" [attr.aria-busy]="loading()">
<header class="profiles__header">
<div>
<h2 class="profiles__title">Risk Profiles</h2>
<p class="profiles__subtitle">Manage risk evaluation profiles and signal weights.</p>
</div>
<div class="profiles__actions">
<div class="profiles__actions">
<stella-filter-chip
label="Status"
[value]="statusFilter() ?? ''"
@@ -48,7 +43,6 @@ import { StellaFilterChipComponent } from '../../shared/components/stella-filter
New Profile
</a>
</div>
</header>
@if (profiles().length > 0) {
<div class="profile-grid">
@@ -179,32 +173,12 @@ import { StellaFilterChipComponent } from '../../shared/components/stella-filter
padding: 1.5rem;
}
.profiles__header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
gap: 1rem;
flex-wrap: wrap;
}
.profiles__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.profiles__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.profiles__actions {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
}
.btn {

View File

@@ -40,12 +40,7 @@ interface SchemaSection {
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="docs">
<header class="docs__header">
<div>
<h2 class="docs__title">Risk Profile Schema Documentation</h2>
<p class="docs__subtitle">Reference documentation for risk profile configuration schemas.</p>
</div>
<div class="docs__actions">
<div class="docs__actions">
<input
type="search"
[(ngModel)]="searchQuery"
@@ -60,7 +55,6 @@ interface SchemaSection {
Try in Playground
</a>
</div>
</header>
<div class="docs__content">
<!-- Navigation Sidebar -->
@@ -300,32 +294,12 @@ interface SchemaSection {
padding: 1.5rem;
}
.docs__header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
gap: 1rem;
flex-wrap: wrap;
}
.docs__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.docs__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.docs__actions {
display: flex;
justify-content: flex-end;
gap: 0.75rem;
align-items: center;
margin-bottom: 1rem;
}
.search-input {

View File

@@ -23,12 +23,7 @@ import {
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="playground">
<header class="playground__header">
<div>
<h2 class="playground__title">Schema Validation Playground</h2>
<p class="playground__subtitle">Test and validate risk profile schemas interactively.</p>
</div>
<div class="playground__actions">
<div class="playground__actions">
<select [(ngModel)]="selectedTemplate" (change)="loadTemplate()" class="form-select">
<option value="">Load Template...</option>
@for (template of templates; track template.id) {
@@ -45,7 +40,6 @@ import {
{{ validating() ? 'Validating...' : 'Validate Schema' }}
</button>
</div>
</header>
<div class="playground__content">
<!-- Editor Panel -->
@@ -265,32 +259,12 @@ import {
padding: 1.5rem;
}
.playground__header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
gap: 1rem;
flex-wrap: wrap;
}
.playground__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.playground__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.playground__actions {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
align-items: center;
margin-bottom: 1rem;
}
.form-select {

View File

@@ -29,13 +29,6 @@ import { ModalComponent } from '../../shared/components/modal/modal.component';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="sealed" [attr.aria-busy]="loading()">
<header class="sealed__header">
<div>
<h2 class="sealed__title">Sealed Mode Control</h2>
<p class="sealed__subtitle">Manage air-gapped operation mode and trusted source overrides.</p>
</div>
</header>
@if (status(); as s) {
<!-- Status Card -->
<div class="status-card" [class.status-card--sealed]="s.isSealed">
@@ -325,23 +318,6 @@ import { ModalComponent } from '../../shared/components/modal/modal.component';
padding: 1.5rem;
}
.sealed__header {
margin-bottom: 1.5rem;
}
.sealed__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.sealed__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
/* Status Card */
.status-card {
display: flex;

View File

@@ -26,23 +26,14 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="overrides" [attr.aria-busy]="loading()">
<header class="overrides__header">
<div>
<nav class="breadcrumb">
<a routerLink="../" class="breadcrumb__link">Sealed Mode</a>
<span class="breadcrumb__sep">/</span>
<span class="breadcrumb__current">Overrides</span>
</nav>
<h2 class="overrides__title">Override Management</h2>
<p class="overrides__subtitle">Manage temporary bypasses for sealed mode restrictions.</p>
</div>
<div class="overrides__actions">
<button class="btn btn--primary" (click)="showCreateModal.set(true)">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="16" height="16">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
New Override
</button>
</header>
</div>
<!-- Filter Tabs -->
<div class="filter-tabs">
@@ -286,50 +277,11 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
padding: 1.5rem;
}
.overrides__header {
.overrides__actions {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
gap: 1rem;
}
.breadcrumb {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 0.5rem;
font-size: 0.85rem;
margin-bottom: 0.5rem;
}
.breadcrumb__link {
color: var(--color-status-info);
text-decoration: none;
}
.breadcrumb__link:hover {
text-decoration: underline;
}
.breadcrumb__sep {
color: var(--color-text-secondary);
}
.breadcrumb__current {
color: var(--color-text-muted);
}
.overrides__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.overrides__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
margin-bottom: 1rem;
}
.btn {

View File

@@ -28,13 +28,6 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="staleness" [attr.aria-busy]="loading()">
<header class="staleness__header">
<div>
<h2 class="staleness__title">Staleness Configuration</h2>
<p class="staleness__subtitle">Configure data freshness thresholds and enforcement rules.</p>
</div>
</header>
<!-- Current Status -->
@if (statusList().length > 0) {
<section class="status-section">
@@ -217,23 +210,6 @@ import { injectPolicyGovernanceScopeResolver } from './policy-governance-scope';
padding: 1.5rem;
}
.staleness__header {
margin-bottom: 1.5rem;
}
.staleness__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.staleness__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
}
.section-title {
margin: 0 0 1rem;
font-size: 1rem;

View File

@@ -29,12 +29,7 @@ import { ModalComponent } from '../../shared/components/modal/modal.component';
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="trust" [attr.aria-busy]="loading()">
<header class="trust__header">
<div>
<h2 class="trust__title">Trust Weight Configuration</h2>
<p class="trust__subtitle">Configure trust weights for vulnerability sources and issuers.</p>
</div>
<div class="trust__actions">
<div class="trust__actions">
<button class="btn btn--secondary" (click)="openAddModal()">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="16" height="16">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
@@ -42,7 +37,6 @@ import { ModalComponent } from '../../shared/components/modal/modal.component';
Add Weight
</button>
</div>
</header>
@if (config(); as c) {
<!-- Default Weight -->
@@ -248,24 +242,11 @@ import { ModalComponent } from '../../shared/components/modal/modal.component';
padding: 1.5rem;
}
.trust__header {
.trust__actions {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1.5rem;
}
.trust__title {
margin: 0;
font-size: 1.25rem;
font-weight: var(--font-weight-semibold);
color: var(--color-text-heading);
}
.trust__subtitle {
margin: 0.25rem 0 0;
color: var(--color-text-muted);
font-size: 0.9rem;
justify-content: flex-end;
gap: 0.5rem;
margin-bottom: 1rem;
}
.btn {