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,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