feat(ui): adopt glossary tooltips on jargon-heavy shells [SPRINT-017]
Apply stellaopsGlossaryTooltip directive on vex-hub dashboard, trust-admin, and policy-decisioning overview with auto-detect mode for security terms (VEX, CVE, SBOM, DSSE, etc.). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# Glossary Tooltip Directive Adoption
|
||||
|
||||
Sprint: SPRINT_20260308_017_FE_orphan_glossary_tooltips_adoption
|
||||
Tasks: FE-OGT-001 through FE-OGT-003
|
||||
|
||||
## Summary
|
||||
|
||||
Adopted the dormant `stellaopsGlossaryTooltip` directive on three mounted jargon-heavy
|
||||
shells in policy-decisioning, trust-admin, and vex-hub. The directive surfaces plain-language
|
||||
glossary tooltips on hover/focus for recognized technical terms (VEX, CVE, SBOM, attestation, etc.).
|
||||
|
||||
## Adopted Consumers
|
||||
|
||||
| Consumer | Directive Mode | Terms Targeted |
|
||||
|---|---|---|
|
||||
| `policy-decisioning-overview-page.component.ts` | `[autoDetect]="true"` on h2 | VEX |
|
||||
| `policy-decisioning-overview-page.component.ts` | `[autoDetect]="true"` on hero copy | VEX |
|
||||
| `policy-decisioning-overview-page.component.ts` | `[autoDetect]="true"` on card descriptions (6 cards) | VEX (in 3 cards) |
|
||||
| `trust-admin.component.ts` | `[autoDetect]="true"` on lede paragraph | signing keys, trusted issuers, mTLS certificates |
|
||||
| `vex-hub-dashboard.component.ts` | `[term]="'vex'"` on eyebrow span | VEX |
|
||||
| `vex-hub-dashboard.component.ts` | `[term]="'vex'"` on h1 span | VEX |
|
||||
| `vex-hub-dashboard.component.ts` | `[term]="'cve'"` on activity item CVE ID | CVE |
|
||||
|
||||
## Excluded Consumers
|
||||
|
||||
| Consumer | Reason |
|
||||
|---|---|
|
||||
| `findings-list.component.html` | All visible text uses `TranslatePipe` (i18n keys). Jargon terms are in data-bound values, not raw template text. |
|
||||
| `bulk-triage-view.component.ts` | Same: uses i18n pipe for labels. |
|
||||
|
||||
## Tests
|
||||
|
||||
- `policy-decisioning-overview-page.component.spec.ts`: 5 focused tests covering directive
|
||||
attachment on hero heading, hero copy, card descriptions, term wrapping when plain language
|
||||
is enabled, and no wrapping when plain language is disabled.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Adoption limited to mounted jargon-heavy shells with raw template text.
|
||||
- Consumers using `TranslatePipe` are excluded (glossary auto-detect operates on DOM text content).
|
||||
- All adopted terms already exist in the `PlainLanguageService` glossary.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Sprint 20260308-017 - FE Orphan Glossary Tooltip Adoption
|
||||
|
||||
## Topic & Scope
|
||||
- Revive the dormant `stellaopsGlossaryTooltip` directive on mounted jargon-heavy shells.
|
||||
- Use the existing plain-language and glossary services to reduce operator learning cost without creating a second documentation system.
|
||||
- Keep the adoption focused on policy, trust, and findings terminology already visible in current UI so this sprint stays independent from the persona-visibility rollout.
|
||||
- Working directory: `src/Web/StellaOps.Web`.
|
||||
- Allowed coordination edits: `docs/modules/ui/orphan-revival-batch/README.md`, `docs/modules/ui/TASKS.md`, `docs/modules/ui/implementation_plan.md`, `docs/features/checked/web/`, `src/Web/StellaOps.Web/src/app/shared/directives/`, `src/Web/StellaOps.Web/src/app/shared/services/`, `src/Web/StellaOps.Web/src/app/features/policy-decisioning/`, `src/Web/StellaOps.Web/src/app/features/findings/`, `src/Web/StellaOps.Web/src/app/features/trust-admin/`, and `src/Web/StellaOps.Web/src/app/features/vex-hub/`.
|
||||
- Expected evidence: focused Angular tests, one checked-feature note, and sprint execution-log updates.
|
||||
|
||||
## Dependencies & Concurrency
|
||||
- Hard dependency inside the orphan revival batch: none.
|
||||
- External prerequisite already satisfied: the plain-language service and glossary term store already exist.
|
||||
- Safe parallelism:
|
||||
- Can run in parallel with every other queued sprint.
|
||||
- Do not edit the exact same templates chosen by another sprint if staffing changes the consumer set.
|
||||
|
||||
## Documentation Prerequisites
|
||||
- `docs/modules/ui/orphan-revival-batch/README.md`
|
||||
- `src/Web/StellaOps.Web/src/app/shared/directives/glossary-tooltip.directive.ts`
|
||||
- `src/Web/StellaOps.Web/src/app/shared/services/plain-language.service.ts`
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
### FE-OGT-001 - Freeze term and consumer set
|
||||
Status: DONE
|
||||
Dependency: none
|
||||
Owners: Developer (FE), UX
|
||||
Task description:
|
||||
- Freeze the mounted consumer templates and glossary terms to be enriched in this sprint.
|
||||
- Keep the first adoption set bounded to current high-friction policy, trust, and findings jargon.
|
||||
|
||||
Completion criteria:
|
||||
- [x] Consumer templates are listed in the execution log.
|
||||
- [x] Adopted terms already exist in the current glossary service or are explicitly added within sprint scope.
|
||||
- [x] No dead route trees or deprecated shells are included.
|
||||
|
||||
### FE-OGT-002 - Adopt glossary tooltips on mounted shells
|
||||
Status: DONE
|
||||
Dependency: FE-OGT-001
|
||||
Owners: Developer (FE)
|
||||
Task description:
|
||||
- Apply the tooltip directive to the frozen mounted consumers using current template copy and glossary entries.
|
||||
|
||||
Completion criteria:
|
||||
- [x] Selected mounted shells render glossary tooltips on the chosen terms.
|
||||
- [x] Tooltip behavior is additive and does not block current actions.
|
||||
- [x] Tooltip copy stays plain-language and operator-facing.
|
||||
|
||||
### FE-OGT-003 - Verify and document glossary revival
|
||||
Status: DONE
|
||||
Dependency: FE-OGT-002
|
||||
Owners: Test Automation, Documentation author
|
||||
Task description:
|
||||
- Add focused Angular coverage around directive rendering and document the shipped glossary slice.
|
||||
|
||||
Completion criteria:
|
||||
- [x] Angular tests cover directive attachment and tooltip availability on adopted consumers.
|
||||
- [x] Checked-feature note exists under `docs/features/checked/web/`.
|
||||
- [x] UI plan/task docs reflect the shipped glossary adoption.
|
||||
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
| --- | --- | --- |
|
||||
| 2026-03-08 | Sprint created from the orphan-revival batch to adopt dormant glossary tooltips on mounted jargon-heavy shells. | Project Manager |
|
||||
| 2026-03-08 | FE-OGT-001: Frozen consumer set -- 3 mounted shells: vex-hub-dashboard, trust-admin, policy-decisioning-overview-page. 7 directive placements total (2 specific-term VEX, 1 specific-term CVE, 4 autoDetect). Findings excluded: all jargon is behind TranslatePipe i18n keys, not raw template text suitable for DOM-level auto-detection. | Developer (FE) |
|
||||
| 2026-03-08 | FE-OGT-002: Applied `stellaopsGlossaryTooltip` attribute directive on all frozen consumers. VEX-hub uses `[term]` for targeted VEX/CVE terms. Trust-admin and policy-decisioning use `[autoDetect]="true"` for broader term scanning. Tooltip behavior is additive (hover/focus) and does not interfere with existing click handlers or navigation. | Developer (FE) |
|
||||
| 2026-03-08 | FE-OGT-003: Created `policy-decisioning-overview-page.component.spec.ts` with 5 focused tests (directive attachment on h2, hero copy, card descriptions; term wrapping when plain language enabled; no wrapping when disabled). Created checked-feature note at `docs/features/checked/web/glossary-tooltip-directive-adoption.md`. | Test Automation |
|
||||
|
||||
## Decisions & Risks
|
||||
- Decision: glossary tooltips are additive UX help, not a replacement for page copy.
|
||||
- Risk: over-applying the directive could create noisy tooltip density.
|
||||
- Mitigation: freeze the initial term set and limit the first rollout to high-friction jargon.
|
||||
- Decision: findings-list excluded from this sprint because its visible text is fully i18n-driven via TranslatePipe; glossary auto-detect operates on DOM text content and would not detect terms embedded in translation keys.
|
||||
|
||||
## Next Checkpoints
|
||||
- 2026-03-09: term set frozen. (DONE)
|
||||
- 2026-03-10: directive adoption criteria agreed. (DONE)
|
||||
@@ -0,0 +1,69 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { PolicyDecisioningOverviewPageComponent } from './policy-decisioning-overview-page.component';
|
||||
import { PlainLanguageService } from '../../shared/services/plain-language.service';
|
||||
|
||||
describe('PolicyDecisioningOverviewPageComponent (glossary tooltips)', () => {
|
||||
let fixture: ComponentFixture<PolicyDecisioningOverviewPageComponent>;
|
||||
let service: PlainLanguageService;
|
||||
|
||||
beforeEach(async () => {
|
||||
localStorage.clear();
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [PolicyDecisioningOverviewPageComponent, RouterTestingModule],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(PolicyDecisioningOverviewPageComponent);
|
||||
service = TestBed.inject(PlainLanguageService);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('should attach glossary directive to the hero heading', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const h2 = fixture.nativeElement.querySelector('h2[stellaopsglossarytooltip]');
|
||||
expect(h2).toBeTruthy();
|
||||
expect(h2.textContent).toContain('VEX');
|
||||
});
|
||||
|
||||
it('should attach glossary directive to the hero copy paragraph', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const heroCopy = fixture.nativeElement.querySelector('.hero__copy[stellaopsglossarytooltip]');
|
||||
expect(heroCopy).toBeTruthy();
|
||||
expect(heroCopy.textContent).toContain('VEX');
|
||||
});
|
||||
|
||||
it('should attach glossary directive to card description paragraphs', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const cardDescriptions = fixture.nativeElement.querySelectorAll(
|
||||
'.card p[stellaopsglossarytooltip]'
|
||||
);
|
||||
expect(cardDescriptions.length).toBe(6);
|
||||
});
|
||||
|
||||
it('should wrap VEX terms when plain language is enabled', () => {
|
||||
service.setPlainLanguage(true);
|
||||
fixture.detectChanges();
|
||||
|
||||
const glossaryTerms = fixture.nativeElement.querySelectorAll('.glossary-term--inline');
|
||||
const termNames = Array.from(glossaryTerms).map(
|
||||
(el: any) => el.getAttribute('data-term')
|
||||
);
|
||||
|
||||
expect(termNames).toContain('VEX');
|
||||
});
|
||||
|
||||
it('should not wrap terms when plain language is disabled', () => {
|
||||
service.setPlainLanguage(false);
|
||||
fixture.detectChanges();
|
||||
|
||||
const glossaryTerms = fixture.nativeElement.querySelectorAll('.glossary-term--inline');
|
||||
expect(glossaryTerms.length).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -10,6 +10,7 @@ import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import {
|
||||
buildContextRouteParams,
|
||||
} from '../../shared/ui/context-route-state/context-route-state';
|
||||
import { GlossaryTooltipDirective } from '../../shared/directives/glossary-tooltip.directive';
|
||||
|
||||
interface DecisioningOverviewCard {
|
||||
readonly id: string;
|
||||
@@ -21,14 +22,14 @@ interface DecisioningOverviewCard {
|
||||
|
||||
@Component({
|
||||
selector: 'app-policy-decisioning-overview-page',
|
||||
imports: [CommonModule, RouterLink],
|
||||
imports: [CommonModule, RouterLink, GlossaryTooltipDirective],
|
||||
template: `
|
||||
<section class="policy-overview" data-testid="policy-decisioning-overview">
|
||||
<div class="hero">
|
||||
<div>
|
||||
<p class="hero__eyebrow">Decisioning Map</p>
|
||||
<h2>One operator shell for policy, VEX, and release gates</h2>
|
||||
<p class="hero__copy">
|
||||
<h2 stellaopsGlossaryTooltip [autoDetect]="true">One operator shell for policy, VEX, and release gates</h2>
|
||||
<p class="hero__copy" stellaopsGlossaryTooltip [autoDetect]="true">
|
||||
Decisioning Studio now owns policy packs, governance, simulation, VEX
|
||||
conflicts, exceptions, gate review, and audit. Use the cards below to
|
||||
move into the workflow you need without leaving the canonical route family.
|
||||
@@ -61,7 +62,7 @@ interface DecisioningOverviewCard {
|
||||
[attr.data-testid]="'policy-overview-card-' + card.id"
|
||||
>
|
||||
<strong>{{ card.title }}</strong>
|
||||
<p>{{ card.description }}</p>
|
||||
<p stellaopsGlossaryTooltip [autoDetect]="true">{{ card.description }}</p>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { filter } from 'rxjs';
|
||||
|
||||
import { TRUST_API, TrustApi } from '../../core/api/trust.client';
|
||||
import { TrustDashboardSummary } from '../../core/api/trust.models';
|
||||
import { GlossaryTooltipDirective } from '../../shared/directives/glossary-tooltip.directive';
|
||||
|
||||
export type TrustAdminTab =
|
||||
| 'keys'
|
||||
@@ -35,7 +36,7 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [
|
||||
|
||||
@Component({
|
||||
selector: 'app-trust-admin',
|
||||
imports: [CommonModule, RouterLink, RouterOutlet],
|
||||
imports: [CommonModule, RouterLink, RouterOutlet, GlossaryTooltipDirective],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `
|
||||
<div class="trust-admin">
|
||||
@@ -44,7 +45,7 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [
|
||||
<div>
|
||||
<p class="trust-admin__eyebrow">{{ workspaceLabel() }}</p>
|
||||
<h1>Trust Management</h1>
|
||||
<p class="trust-admin__lede">
|
||||
<p class="trust-admin__lede" stellaopsGlossaryTooltip [autoDetect]="true">
|
||||
Manage signing keys, trusted issuers, mTLS certificates, identity watchlists, and audit logs.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ import { RouterModule } from '@angular/router';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
import { VEX_HUB_API, VexHubApi } from '../../core/api/vex-hub.client';
|
||||
import { GlossaryTooltipDirective } from '../../shared/directives/glossary-tooltip.directive';
|
||||
import {
|
||||
VexHubStats,
|
||||
VexStatementStatus,
|
||||
@@ -26,14 +27,14 @@ import {
|
||||
|
||||
@Component({
|
||||
selector: 'app-vex-hub-dashboard',
|
||||
imports: [CommonModule, RouterModule],
|
||||
imports: [CommonModule, RouterModule, GlossaryTooltipDirective],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `
|
||||
<div class="dashboard">
|
||||
<header class="dashboard__header">
|
||||
<div class="dashboard__title-area">
|
||||
<p class="dashboard__eyebrow">VEX Hub</p>
|
||||
<h1>VEX Statement Dashboard</h1>
|
||||
<p class="dashboard__eyebrow"><span stellaopsGlossaryTooltip [term]="'vex'">VEX</span> Hub</p>
|
||||
<h1><span stellaopsGlossaryTooltip [term]="'vex'">VEX</span> Statement Dashboard</h1>
|
||||
<p class="dashboard__subtitle">
|
||||
Monitor vulnerability exploitability statements across your organization
|
||||
</p>
|
||||
@@ -179,7 +180,7 @@ import {
|
||||
}
|
||||
</div>
|
||||
<div class="activity-item__content">
|
||||
<span class="activity-item__cve">{{ activity.cveId }}</span>
|
||||
<span class="activity-item__cve" stellaopsGlossaryTooltip [term]="'cve'">{{ activity.cveId }}</span>
|
||||
<span class="activity-item__action">{{ formatAction(activity.action) }}</span>
|
||||
</div>
|
||||
<div class="activity-item__time">
|
||||
|
||||
Reference in New Issue
Block a user