theme and search fixes
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
import { AppConfigService } from '../config/app-config.service';
|
||||
import { AuthHttpInterceptor } from '../auth/auth-http.interceptor';
|
||||
import { AuthorityAuthService } from '../auth/authority-auth.service';
|
||||
import { DpopService } from '../auth/dpop/dpop.service';
|
||||
import { TenantActivationService } from '../auth/tenant-activation.service';
|
||||
import { AUDIT_BUNDLES_API_BASE_URL, AuditBundlesHttpClient } from './audit-bundles.client';
|
||||
|
||||
describe('AuditBundlesHttpClient', () => {
|
||||
let client: AuditBundlesHttpClient;
|
||||
let httpMock: HttpTestingController;
|
||||
let auth: Pick<AuthorityAuthService, 'getAuthHeadersForRequest'> & {
|
||||
getAuthHeadersForRequest: jasmine.Spy;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
auth = {
|
||||
getAuthHeadersForRequest: jasmine
|
||||
.createSpy('getAuthHeadersForRequest')
|
||||
.and.returnValue(
|
||||
Promise.resolve({
|
||||
authorization: 'DPoP access-token',
|
||||
dpop: 'proof-token',
|
||||
})
|
||||
),
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideHttpClientTesting(),
|
||||
AuditBundlesHttpClient,
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: AuthHttpInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: AuthorityAuthService,
|
||||
useValue: auth,
|
||||
},
|
||||
{
|
||||
provide: AppConfigService,
|
||||
useValue: {
|
||||
authority: {
|
||||
issuer: 'https://stella-ops.local',
|
||||
tokenEndpoint: '/connect/token',
|
||||
authorizeEndpoint: '/connect/authorize',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: DpopService,
|
||||
useValue: {
|
||||
setNonce: jasmine.createSpy('setNonce').and.returnValue(Promise.resolve()),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: TenantActivationService,
|
||||
useValue: {
|
||||
activeTenantId: () => 'demo-prod',
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: AUDIT_BUNDLES_API_BASE_URL,
|
||||
useValue: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
client = TestBed.inject(AuditBundlesHttpClient);
|
||||
httpMock = TestBed.inject(HttpTestingController);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
httpMock.verify();
|
||||
});
|
||||
|
||||
it('leaves auth to the shared interceptor so audit bundle creation uses DPoP headers', async () => {
|
||||
const responsePromise = firstValueFrom(client.createBundle({
|
||||
subject: {
|
||||
type: 'IMAGE',
|
||||
name: 'asset-web-prod',
|
||||
digest: { sha256: 'sha256:test-bundle-probe' },
|
||||
},
|
||||
contents: {
|
||||
vulnReports: true,
|
||||
sbom: true,
|
||||
vex: true,
|
||||
policyEvals: true,
|
||||
attestations: true,
|
||||
},
|
||||
}));
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
const request = httpMock.expectOne((pending) => pending.url === '/v1/audit-bundles');
|
||||
expect(auth.getAuthHeadersForRequest).toHaveBeenCalledOnceWith(
|
||||
`${window.location.origin}/v1/audit-bundles`,
|
||||
'POST'
|
||||
);
|
||||
expect(request.request.headers.get('Authorization')).toBe('DPoP access-token');
|
||||
expect(request.request.headers.get('DPoP')).toBe('proof-token');
|
||||
expect(request.request.headers.get('X-Stella-Tenant')).toBe('demo-prod');
|
||||
request.flush({
|
||||
bundleId: 'bndl-0001',
|
||||
status: 'queued',
|
||||
statusUrl: '/v1/audit-bundles/bndl-0001',
|
||||
});
|
||||
await responsePromise;
|
||||
});
|
||||
|
||||
it('uses the interceptor for audit bundle downloads too', async () => {
|
||||
const responsePromise = firstValueFrom(client.downloadBundle('bndl-0001'));
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
const request = httpMock.expectOne((pending) => pending.url === '/v1/audit-bundles/bndl-0001/download');
|
||||
expect(request.request.headers.get('Authorization')).toBe('DPoP access-token');
|
||||
expect(request.request.headers.get('DPoP')).toBe('proof-token');
|
||||
expect(request.request.headers.get('Accept')).toBe('application/zip');
|
||||
request.flush(new Blob(['bundle'], { type: 'application/zip' }));
|
||||
await responsePromise;
|
||||
});
|
||||
});
|
||||
@@ -2,7 +2,6 @@ import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Inject, Injectable, InjectionToken, inject } from '@angular/core';
|
||||
import { Observable, of, delay, map, catchError, throwError } from 'rxjs';
|
||||
|
||||
import { AuthSessionStore } from '../auth/auth-session.store';
|
||||
import { TenantActivationService } from '../auth/tenant-activation.service';
|
||||
import { generateTraceId } from './trace.util';
|
||||
import type {
|
||||
@@ -82,7 +81,6 @@ export class AuditBundlesHttpClient implements AuditBundlesApi {
|
||||
|
||||
constructor(
|
||||
private readonly http: HttpClient,
|
||||
private readonly authSession: AuthSessionStore,
|
||||
@Inject(AUDIT_BUNDLES_API_BASE_URL) private readonly baseUrl: string
|
||||
) {}
|
||||
|
||||
@@ -210,11 +208,6 @@ export class AuditBundlesHttpClient implements AuditBundlesApi {
|
||||
Accept: 'application/json',
|
||||
});
|
||||
|
||||
const accessToken = this.authSession.session()?.tokens.accessToken;
|
||||
if (accessToken) {
|
||||
headers = headers.set('Authorization', `Bearer ${accessToken}`);
|
||||
}
|
||||
|
||||
if (projectId) headers = headers.set('X-Stella-Project', projectId);
|
||||
|
||||
return headers;
|
||||
|
||||
@@ -138,7 +138,7 @@ interface LoadedBundle {
|
||||
.management-header h2 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-heading);
|
||||
margin: 0 0 0.25rem;
|
||||
}
|
||||
|
||||
@@ -161,8 +161,8 @@ interface LoadedBundle {
|
||||
}
|
||||
|
||||
.section-card {
|
||||
background: rgba(30, 41, 59, 0.4);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-secondary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.5rem;
|
||||
}
|
||||
@@ -170,7 +170,7 @@ interface LoadedBundle {
|
||||
.section-card h3 {
|
||||
font-size: 1rem;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-heading);
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
@@ -187,8 +187,8 @@ interface LoadedBundle {
|
||||
}
|
||||
|
||||
.bundle-card {
|
||||
background: rgba(15, 23, 42, 0.5);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -258,7 +258,7 @@ interface LoadedBundle {
|
||||
|
||||
.meta-value {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.bundle-actions {
|
||||
@@ -273,8 +273,8 @@ interface LoadedBundle {
|
||||
}
|
||||
|
||||
.category-card {
|
||||
background: rgba(15, 23, 42, 0.5);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -297,7 +297,7 @@ interface LoadedBundle {
|
||||
|
||||
.category-name {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-heading);
|
||||
}
|
||||
|
||||
.category-count {
|
||||
@@ -316,7 +316,7 @@ interface LoadedBundle {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.375rem 0.5rem;
|
||||
background: rgba(30, 41, 59, 0.5);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
@@ -353,8 +353,8 @@ interface LoadedBundle {
|
||||
}
|
||||
|
||||
.btn--secondary {
|
||||
background: var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
background: var(--color-surface-tertiary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.btn--danger {
|
||||
|
||||
@@ -73,7 +73,7 @@ import { OfflineModeService } from '../../core/services/offline-mode.service';
|
||||
styles: [`
|
||||
.offline-kit-layout {
|
||||
min-height: 100%;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
@@ -81,13 +81,13 @@ import { OfflineModeService } from '../../core/services/offline-mode.service';
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
padding: 1.5rem 2rem;
|
||||
border-bottom: 1px solid var(--color-text-primary);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-surface-tertiary);
|
||||
color: var(--color-text-heading);
|
||||
margin: 0 0 0.25rem;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ import { OfflineModeService } from '../../core/services/offline-mode.service';
|
||||
}
|
||||
|
||||
.page-shortcuts a {
|
||||
border: 1px solid var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-full);
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.72rem;
|
||||
@@ -114,8 +114,8 @@ import { OfflineModeService } from '../../core/services/offline-mode.service';
|
||||
}
|
||||
|
||||
.page-shortcuts a:hover {
|
||||
color: var(--color-border-primary);
|
||||
border-color: var(--color-border-primary);
|
||||
color: var(--color-text-link);
|
||||
border-color: var(--color-text-link);
|
||||
}
|
||||
|
||||
.connection-status {
|
||||
@@ -159,8 +159,8 @@ import { OfflineModeService } from '../../core/services/offline-mode.service';
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
padding: 0 2rem;
|
||||
background: var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.tab-link {
|
||||
|
||||
@@ -103,29 +103,29 @@ import { PolicyPackStore } from '../services/policy-pack.store';
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
:host { display: block; background: var(--color-surface-inverse); color: var(--color-border-primary); min-height: 100vh; }
|
||||
:host { display: block; background: var(--color-surface-primary); color: var(--color-text-primary); min-height: 100vh; }
|
||||
.workspace { max-width: 1200px; margin: 0 auto; padding: 1.5rem; }
|
||||
.workspace__header { margin-bottom: 1rem; }
|
||||
.workspace__eyebrow { margin: 0; color: var(--color-status-info); text-transform: uppercase; letter-spacing: 0.05em; font-size: 0.8rem; }
|
||||
.workspace__lede { margin: 0.2rem 0 0; color: var(--color-text-muted); }
|
||||
.workspace__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 1rem; }
|
||||
.pack-card { background: var(--color-text-heading); border: 1px solid var(--color-text-heading); border-radius: var(--radius-xl); padding: 1rem; box-shadow: 0 12px 30px rgba(0,0,0,0.28); display: grid; gap: 0.6rem; }
|
||||
.pack-card { background: var(--color-surface-elevated); border: 1px solid var(--color-border-primary); border-radius: var(--radius-xl); padding: 1rem; box-shadow: var(--shadow-md); display: grid; gap: 0.6rem; }
|
||||
.pack-card__head { display: flex; justify-content: space-between; gap: 0.75rem; align-items: flex-start; }
|
||||
.pack-card__eyebrow { margin: 0; color: var(--color-brand-muted); font-size: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase; }
|
||||
.pack-card__desc { margin: 0.2rem 0 0; color: rgba(212, 201, 168, 0.5); }
|
||||
.pack-card__eyebrow { margin: 0; color: var(--color-brand-secondary); font-size: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase; }
|
||||
.pack-card__desc { margin: 0.2rem 0 0; color: var(--color-text-muted); }
|
||||
.pack-card__meta { display: grid; justify-items: end; gap: 0.2rem; color: var(--color-text-muted); font-size: 0.9rem; }
|
||||
.pack-card__tags { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 0.35rem; }
|
||||
.pack-card__tags li { padding: 0.2rem 0.45rem; border: 1px solid var(--color-text-heading); border-radius: var(--radius-full); background: var(--color-surface-inverse); }
|
||||
.pack-card__tags li { padding: 0.2rem 0.45rem; border: 1px solid var(--color-border-primary); border-radius: var(--radius-full); background: var(--color-surface-tertiary); }
|
||||
.pack-card__actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
|
||||
.pack-card__actions a { color: var(--color-border-primary); border: 1px solid var(--color-text-primary); border-radius: var(--radius-lg); padding: 0.35rem 0.6rem; text-decoration: none; }
|
||||
.pack-card__actions a { color: var(--color-text-primary); border: 1px solid var(--color-border-primary); border-radius: var(--radius-lg); padding: 0.35rem 0.6rem; text-decoration: none; }
|
||||
.pack-card__actions a:hover { border-color: var(--color-status-info); }
|
||||
.pack-card__actions a.action-disabled { opacity: 0.5; pointer-events: none; border-style: dashed; }
|
||||
.pack-card__detail { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.35rem 1rem; margin: 0; }
|
||||
dt { color: var(--color-text-muted); font-size: 0.85rem; margin: 0; }
|
||||
dd { margin: 0; color: var(--color-border-primary); }
|
||||
.workspace__banner { background: var(--color-text-heading); border: 1px solid var(--color-text-primary); color: var(--color-status-warning-border); padding: 0.75rem 1rem; border-radius: var(--radius-xl); margin: 0.5rem 0 1rem; }
|
||||
dd { margin: 0; color: var(--color-text-primary); }
|
||||
.workspace__banner { background: var(--color-status-warning-bg); border: 1px solid var(--color-status-warning-border); color: var(--color-status-warning-text); padding: 0.75rem 1rem; border-radius: var(--radius-xl); margin: 0.5rem 0 1rem; }
|
||||
.workspace__footer { margin-top: 0.8rem; }
|
||||
.workspace__footer button { background: var(--color-status-info-text); border: 1px solid var(--color-status-info-text); color: var(--color-border-primary); border-radius: var(--radius-lg); padding: 0.45rem 0.8rem; }
|
||||
.workspace__footer button { background: var(--color-brand-primary); border: 1px solid var(--color-brand-primary); color: var(--color-text-inverse); border-radius: var(--radius-lg); padding: 0.45rem 0.8rem; cursor: pointer; }
|
||||
`,
|
||||
]
|
||||
})
|
||||
|
||||
@@ -313,7 +313,7 @@ export type AirgapEventType =
|
||||
}
|
||||
|
||||
.status-info strong {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
@@ -344,15 +344,15 @@ export type AirgapEventType =
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@@ -384,10 +384,10 @@ export type AirgapEventType =
|
||||
|
||||
.filter-group input,
|
||||
.filter-group select {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
padding: 0.5rem 0.75rem;
|
||||
min-width: 160px;
|
||||
}
|
||||
@@ -430,8 +430,8 @@ export type AirgapEventType =
|
||||
}
|
||||
|
||||
.event-card {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
@@ -439,7 +439,7 @@ export type AirgapEventType =
|
||||
}
|
||||
|
||||
.event-card:hover {
|
||||
border-color: var(--color-text-primary);
|
||||
border-color: var(--color-border-primary);
|
||||
}
|
||||
|
||||
.event-card--warning {
|
||||
@@ -555,7 +555,7 @@ export type AirgapEventType =
|
||||
.event-card__details {
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.event-card__details h4 {
|
||||
@@ -567,10 +567,10 @@ export type AirgapEventType =
|
||||
.details-json {
|
||||
margin: 0;
|
||||
padding: 0.75rem;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@@ -581,13 +581,13 @@ export type AirgapEventType =
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
margin-top: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.airgap-audit__pagination button {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -506,7 +506,7 @@ import {
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-elevated);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
@@ -522,7 +522,7 @@ import {
|
||||
|
||||
.alert-name {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.alert-type {
|
||||
@@ -578,10 +578,10 @@ import {
|
||||
|
||||
.filter-group input,
|
||||
.filter-group select {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
padding: 0.5rem 0.75rem;
|
||||
min-width: 160px;
|
||||
}
|
||||
@@ -630,11 +630,11 @@ import {
|
||||
.cert-table td {
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.cert-table th {
|
||||
background: var(--color-surface-inverse);
|
||||
background: var(--color-surface-primary);
|
||||
color: var(--color-text-muted);
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-size: 0.85rem;
|
||||
@@ -679,7 +679,7 @@ import {
|
||||
}
|
||||
|
||||
.cert-name strong {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
@@ -720,7 +720,7 @@ import {
|
||||
}
|
||||
|
||||
.subject-cn {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
font-family: monospace;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
@@ -767,7 +767,7 @@ import {
|
||||
|
||||
.btn-chain {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-status-info);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.15rem 0.4rem;
|
||||
@@ -785,8 +785,8 @@ import {
|
||||
|
||||
.btn-action {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
@@ -806,13 +806,13 @@ import {
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.cert-inventory__pagination button {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
@@ -845,8 +845,8 @@ import {
|
||||
|
||||
.detail-modal,
|
||||
.chain-modal {
|
||||
background: var(--color-text-heading);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-xl);
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
@@ -861,7 +861,7 @@ import {
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.detail-modal__header h3,
|
||||
@@ -872,7 +872,7 @@ import {
|
||||
|
||||
.btn-close {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-muted);
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
@@ -927,7 +927,7 @@ import {
|
||||
|
||||
.detail-item dd {
|
||||
margin: 0;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.mono {
|
||||
@@ -965,7 +965,7 @@ import {
|
||||
.san-list li {
|
||||
font-family: monospace;
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.detail-modal__footer,
|
||||
@@ -974,13 +974,13 @@ import {
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
@@ -1016,8 +1016,8 @@ import {
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
@@ -1035,10 +1035,10 @@ import {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.chain-node--root .chain-node__icon {
|
||||
@@ -1060,7 +1060,7 @@ import {
|
||||
|
||||
.chain-node__name {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.chain-node__cn {
|
||||
|
||||
@@ -329,15 +329,15 @@ export type IncidentType =
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.summary-card:hover {
|
||||
border-color: var(--color-text-primary);
|
||||
border-color: var(--color-border-primary);
|
||||
}
|
||||
|
||||
.summary-card--open { border-left: 3px solid var(--color-status-error); }
|
||||
@@ -349,7 +349,7 @@ export type IncidentType =
|
||||
.summary-value {
|
||||
font-size: 1.75rem;
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@@ -381,10 +381,10 @@ export type IncidentType =
|
||||
|
||||
.filter-group input,
|
||||
.filter-group select {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
padding: 0.5rem 0.75rem;
|
||||
min-width: 160px;
|
||||
}
|
||||
@@ -427,15 +427,15 @@ export type IncidentType =
|
||||
}
|
||||
|
||||
.incident-card {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-xl);
|
||||
overflow: hidden;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
|
||||
.incident-card:hover {
|
||||
border-color: var(--color-text-primary);
|
||||
border-color: var(--color-border-primary);
|
||||
}
|
||||
|
||||
.incident-card--critical {
|
||||
@@ -489,7 +489,7 @@ export type IncidentType =
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.incident-id {
|
||||
@@ -549,9 +549,9 @@ export type IncidentType =
|
||||
}
|
||||
|
||||
.incident-card__details {
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
padding: 1.25rem;
|
||||
background: rgba(15, 23, 42, 0.5);
|
||||
background: var(--color-surface-secondary);
|
||||
}
|
||||
|
||||
.details-section {
|
||||
@@ -581,7 +581,7 @@ export type IncidentType =
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: var(--color-surface-inverse);
|
||||
background: var(--color-surface-primary);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ export type IncidentType =
|
||||
|
||||
.resource-name {
|
||||
flex: 1;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@@ -638,14 +638,14 @@ export type IncidentType =
|
||||
top: 16px;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-border-primary);
|
||||
}
|
||||
|
||||
.timeline-marker {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--color-text-primary);
|
||||
background: var(--color-border-primary);
|
||||
flex-shrink: 0;
|
||||
margin-top: 4px;
|
||||
}
|
||||
@@ -669,7 +669,7 @@ export type IncidentType =
|
||||
.timeline-type {
|
||||
font-size: 0.75rem;
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.timeline-time {
|
||||
@@ -691,10 +691,10 @@ export type IncidentType =
|
||||
.details-json {
|
||||
margin: 0;
|
||||
padding: 0.75rem;
|
||||
background: var(--color-surface-inverse);
|
||||
background: var(--color-surface-primary);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@@ -703,13 +703,13 @@ export type IncidentType =
|
||||
gap: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.btn-action {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.4rem 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
@@ -729,13 +729,13 @@ export type IncidentType =
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
margin-top: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.incident-audit__pagination button {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -289,10 +289,10 @@ import { TrustScoreConfigComponent } from './trust-score-config.component';
|
||||
|
||||
.filter-group input,
|
||||
.filter-group select {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
padding: 0.5rem 0.75rem;
|
||||
min-width: 160px;
|
||||
}
|
||||
@@ -335,7 +335,7 @@ import { TrustScoreConfigComponent } from './trust-score-config.component';
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 1rem;
|
||||
background: var(--color-surface-inverse);
|
||||
background: var(--color-surface-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
@@ -386,11 +386,11 @@ import { TrustScoreConfigComponent } from './trust-score-config.component';
|
||||
.issuer-table td {
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.issuer-table th {
|
||||
background: var(--color-surface-inverse);
|
||||
background: var(--color-surface-primary);
|
||||
color: var(--color-text-muted);
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-size: 0.85rem;
|
||||
@@ -429,7 +429,7 @@ import { TrustScoreConfigComponent } from './trust-score-config.component';
|
||||
}
|
||||
|
||||
.issuer-info strong {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.issuer-name {
|
||||
@@ -466,7 +466,7 @@ import { TrustScoreConfigComponent } from './trust-score-config.component';
|
||||
.score-bar {
|
||||
width: 60px;
|
||||
height: 6px;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -517,8 +517,8 @@ import { TrustScoreConfigComponent } from './trust-score-config.component';
|
||||
|
||||
.btn-action {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
@@ -548,13 +548,13 @@ import { TrustScoreConfigComponent } from './trust-score-config.component';
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.issuer-list__pagination button {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -273,8 +273,8 @@ import {
|
||||
bottom: 0;
|
||||
width: 480px;
|
||||
max-width: 100vw;
|
||||
background: var(--color-text-heading);
|
||||
border-left: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-elevated);
|
||||
border-left: 1px solid var(--color-border-primary);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1000;
|
||||
@@ -286,7 +286,7 @@ import {
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
padding: 1.5rem;
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.detail-panel__header h2 {
|
||||
@@ -303,7 +303,7 @@ import {
|
||||
|
||||
.btn-close {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-muted);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
@@ -356,7 +356,7 @@ import {
|
||||
|
||||
.detail-item dd {
|
||||
margin: 0;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.fingerprint {
|
||||
@@ -428,7 +428,7 @@ import {
|
||||
.breakdown-bar {
|
||||
display: flex;
|
||||
height: 8px;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -479,8 +479,8 @@ import {
|
||||
|
||||
.history-item {
|
||||
padding: 0.75rem;
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
@@ -520,8 +520,8 @@ import {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
@@ -558,7 +558,7 @@ import {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding: 0.35rem 0;
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.metadata-item dt {
|
||||
@@ -568,7 +568,7 @@ import {
|
||||
|
||||
.metadata-item dd {
|
||||
margin: 0;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
font-family: monospace;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
@@ -577,7 +577,7 @@ import {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
@@ -602,8 +602,8 @@ import {
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
@@ -612,7 +612,7 @@ import {
|
||||
|
||||
.btn-danger {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-status-error);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ import { KeyExpiryAlert } from '../../core/api/trust.models';
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.expiry-warnings__title p {
|
||||
@@ -145,8 +145,8 @@ import { KeyExpiryAlert } from '../../core/api/trust.models';
|
||||
|
||||
.btn-toggle {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
@@ -172,8 +172,8 @@ import { KeyExpiryAlert } from '../../core/api/trust.models';
|
||||
}
|
||||
|
||||
.alert-card {
|
||||
background: var(--color-text-heading);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ import { KeyExpiryAlert } from '../../core/api/trust.models';
|
||||
|
||||
.alert-card__name {
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.purpose-badge {
|
||||
@@ -245,7 +245,7 @@ import { KeyExpiryAlert } from '../../core/api/trust.models';
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.suggested-action {
|
||||
|
||||
@@ -334,8 +334,8 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
}
|
||||
|
||||
.wizard-modal {
|
||||
background: var(--color-text-heading);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-elevated);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-2xl);
|
||||
width: 90%;
|
||||
max-width: 640px;
|
||||
@@ -349,7 +349,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.wizard-header h2 {
|
||||
@@ -360,7 +360,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
|
||||
.btn-close {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-muted);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
@@ -400,7 +400,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
color: var(--color-text-secondary);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
transition: all 0.2s;
|
||||
@@ -432,7 +432,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
.progress-connector {
|
||||
width: 40px;
|
||||
height: 2px;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
@@ -467,8 +467,8 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
}
|
||||
|
||||
.key-summary {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -491,7 +491,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.summary-value.mono {
|
||||
@@ -573,16 +573,16 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
|
||||
.form-group label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
padding: 0.6rem 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
@@ -638,7 +638,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
}
|
||||
|
||||
.confirm-value {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.confirm-value.mono {
|
||||
@@ -668,7 +668,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
.rotating-spinner {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 4px solid var(--color-text-heading);
|
||||
border: 4px solid var(--color-surface-tertiary);
|
||||
border-top-color: var(--color-status-info);
|
||||
border-radius: var(--radius-full);
|
||||
animation: spin 1s linear infinite;
|
||||
@@ -722,8 +722,8 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
.new-key-info {
|
||||
margin-top: 1.5rem;
|
||||
padding: 1rem;
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
@@ -741,7 +741,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
}
|
||||
|
||||
.new-key-value {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.new-key-value.mono {
|
||||
@@ -764,7 +764,7 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
@@ -794,8 +794,8 @@ export type WizardStep = 'review' | 'configure' | 'confirm' | 'rotating' | 'comp
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
|
||||
@@ -288,10 +288,10 @@ import { KeyRotationWizardComponent } from './key-rotation-wizard.component';
|
||||
|
||||
.filter-group input,
|
||||
.filter-group select {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
padding: 0.5rem 0.75rem;
|
||||
min-width: 180px;
|
||||
}
|
||||
@@ -340,11 +340,11 @@ import { KeyRotationWizardComponent } from './key-rotation-wizard.component';
|
||||
.key-table td {
|
||||
padding: 0.75rem 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.key-table th {
|
||||
background: var(--color-surface-inverse);
|
||||
background: var(--color-surface-primary);
|
||||
color: var(--color-text-muted);
|
||||
font-weight: var(--font-weight-medium);
|
||||
font-size: 0.85rem;
|
||||
@@ -384,7 +384,7 @@ import { KeyRotationWizardComponent } from './key-rotation-wizard.component';
|
||||
}
|
||||
|
||||
.key-name strong {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.key-desc {
|
||||
@@ -493,8 +493,8 @@ import { KeyRotationWizardComponent } from './key-rotation-wizard.component';
|
||||
|
||||
.btn-action {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.8rem;
|
||||
@@ -528,13 +528,13 @@ import { KeyRotationWizardComponent } from './key-rotation-wizard.component';
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.key-dashboard__pagination button {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -207,8 +207,8 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [
|
||||
styles: [`
|
||||
:host {
|
||||
display: block;
|
||||
background: var(--color-surface-inverse);
|
||||
color: var(--color-border-primary);
|
||||
background: var(--color-surface-primary);
|
||||
color: var(--color-text-primary);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
@@ -257,8 +257,8 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
@@ -297,8 +297,8 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
background: var(--color-text-heading);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-elevated);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -358,7 +358,7 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [
|
||||
.trust-admin__tabs {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [
|
||||
}
|
||||
|
||||
.trust-admin__tab:hover {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.trust-admin__tab--active {
|
||||
@@ -405,8 +405,8 @@ const TRUST_ADMIN_TABS: readonly TrustAdminTab[] = [
|
||||
}
|
||||
|
||||
.trust-admin__content {
|
||||
background: var(--color-text-heading);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-elevated);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-xl);
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
@@ -250,10 +250,10 @@ import {
|
||||
|
||||
.filter-group input,
|
||||
.filter-group select {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
padding: 0.5rem 0.75rem;
|
||||
min-width: 140px;
|
||||
}
|
||||
@@ -315,8 +315,8 @@ import {
|
||||
}
|
||||
|
||||
.event-card {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
@@ -324,7 +324,7 @@ import {
|
||||
}
|
||||
|
||||
.event-card:hover {
|
||||
border-color: var(--color-text-primary);
|
||||
border-color: var(--color-border-primary);
|
||||
}
|
||||
|
||||
.event-card--warning {
|
||||
@@ -368,7 +368,7 @@ import {
|
||||
|
||||
.event-type {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.event-time {
|
||||
@@ -412,7 +412,7 @@ import {
|
||||
.event-card__details {
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.event-details-grid {
|
||||
@@ -435,7 +435,7 @@ import {
|
||||
|
||||
.detail-item dd {
|
||||
margin: 0;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.mono {
|
||||
@@ -464,10 +464,10 @@ import {
|
||||
.change-value {
|
||||
margin: 0;
|
||||
padding: 0.5rem;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@@ -485,10 +485,10 @@ import {
|
||||
.details-value {
|
||||
margin: 0;
|
||||
padding: 0.5rem;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@@ -499,13 +499,13 @@ import {
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
margin-top: 1rem;
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.audit-log__pagination button {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -278,8 +278,8 @@ import {
|
||||
`,
|
||||
styles: [`
|
||||
.config-panel {
|
||||
background: var(--color-surface-inverse);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-xl);
|
||||
margin-bottom: 1.5rem;
|
||||
overflow: hidden;
|
||||
@@ -290,8 +290,8 @@ import {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1rem 1.5rem;
|
||||
background: var(--color-text-heading);
|
||||
border-bottom: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-elevated);
|
||||
border-bottom: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.config-panel__header h3 {
|
||||
@@ -302,7 +302,7 @@ import {
|
||||
|
||||
.btn-close {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-muted);
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
@@ -362,7 +362,7 @@ import {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.weight-value {
|
||||
@@ -374,7 +374,7 @@ import {
|
||||
.weight-control input[type="range"] {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-sm);
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
@@ -395,7 +395,7 @@ import {
|
||||
}
|
||||
|
||||
.preview-section {
|
||||
background: var(--color-text-heading);
|
||||
background: var(--color-surface-tertiary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1rem;
|
||||
}
|
||||
@@ -432,7 +432,7 @@ import {
|
||||
}
|
||||
|
||||
.preview-score--new {
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.preview-score--new.score-up {
|
||||
@@ -486,7 +486,7 @@ import {
|
||||
.impact-value {
|
||||
font-size: 1.25rem;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.impact-label {
|
||||
@@ -513,10 +513,10 @@ import {
|
||||
}
|
||||
|
||||
.threshold-control input[type="number"] {
|
||||
background: var(--color-text-heading);
|
||||
border: 1px solid var(--color-text-primary);
|
||||
background: var(--color-surface-tertiary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
padding: 0.4rem 0.6rem;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -555,8 +555,8 @@ import {
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem 1.5rem;
|
||||
background: var(--color-text-heading);
|
||||
border-top: 1px solid var(--color-text-heading);
|
||||
background: var(--color-surface-elevated);
|
||||
border-top: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.btn-save,
|
||||
@@ -586,8 +586,8 @@ import {
|
||||
|
||||
.btn-cancel {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
color: var(--color-border-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
@@ -596,7 +596,7 @@ import {
|
||||
|
||||
.btn-reset {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
color: var(--color-status-warning-border);
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
@@ -122,29 +122,15 @@ interface NavSectionGroup {
|
||||
<div class="sb-divider"></div>
|
||||
}
|
||||
@if (!effectiveCollapsed && section.displayChildren.length > 0) {
|
||||
<!-- Section with foldable children: link + chevron toggle -->
|
||||
<div class="sb-section" [class.sb-section--folded]="sidebarPrefs.collapsedSections().has(section.id)">
|
||||
<div class="sb-section__head">
|
||||
<app-sidebar-nav-item
|
||||
[label]="section.label"
|
||||
[icon]="section.icon"
|
||||
[route]="section.route"
|
||||
[badge]="section.sectionBadge"
|
||||
[collapsed]="effectiveCollapsed"
|
||||
></app-sidebar-nav-item>
|
||||
<button
|
||||
type="button"
|
||||
class="sb-section__chevron"
|
||||
(click)="sidebarPrefs.toggleSection(section.id)"
|
||||
[attr.aria-expanded]="!sidebarPrefs.collapsedSections().has(section.id)"
|
||||
[attr.aria-controls]="'nav-sec-' + section.id"
|
||||
[attr.aria-label]="(sidebarPrefs.collapsedSections().has(section.id) ? 'Expand ' : 'Collapse ') + section.label"
|
||||
>
|
||||
<svg class="sb-section__chevron-icon" viewBox="0 0 16 16" width="10" height="10" aria-hidden="true">
|
||||
<path d="M4 6l4 4.5 4-4.5z" fill="currentColor"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Section with children: link + always-visible sub-items -->
|
||||
<div class="sb-section">
|
||||
<app-sidebar-nav-item
|
||||
[label]="section.label"
|
||||
[icon]="section.icon"
|
||||
[route]="section.route"
|
||||
[badge]="section.sectionBadge"
|
||||
[collapsed]="effectiveCollapsed"
|
||||
></app-sidebar-nav-item>
|
||||
<div class="sb-section__body" [id]="'nav-sec-' + section.id">
|
||||
<div class="sb-section__body-inner">
|
||||
@for (child of section.displayChildren; track child.id) {
|
||||
@@ -247,7 +233,6 @@ interface NavSectionGroup {
|
||||
|
||||
.sidebar--collapsed.sidebar--flyout .sb-group__header,
|
||||
.sidebar--collapsed.sidebar--flyout .sb-divider,
|
||||
.sidebar--collapsed.sidebar--flyout .sb-section__head,
|
||||
.sidebar--collapsed.sidebar--flyout .sb-section__body {
|
||||
animation: flyoutFadeIn 0.2s ease-out both;
|
||||
}
|
||||
@@ -477,83 +462,15 @@ interface NavSectionGroup {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
/* Section head: nav-item + chevron */
|
||||
.sb-section__head {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sb-section__head > app-sidebar-nav-item {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.sb-section__chevron {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
background: transparent;
|
||||
color: var(--color-sidebar-text-muted);
|
||||
cursor: pointer;
|
||||
opacity: 0.25;
|
||||
transition: opacity 0.2s, background 0.2s, color 0.2s, transform 0.15s;
|
||||
margin-right: 0.25rem;
|
||||
|
||||
&:hover {
|
||||
opacity: 1 !important;
|
||||
background: rgba(245, 166, 35, 0.12);
|
||||
color: var(--color-sidebar-active-text);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
opacity: 1 !important;
|
||||
outline: 1.5px solid var(--color-sidebar-active-border);
|
||||
outline-offset: -1.5px;
|
||||
}
|
||||
}
|
||||
|
||||
.sb-section__head:hover .sb-section__chevron {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.sb-section--folded .sb-section__chevron {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.sb-section__chevron-icon {
|
||||
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
.sb-section--folded .sb-section__chevron-icon {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
/* Animated section body */
|
||||
/* Section children */
|
||||
.sb-section__body {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr;
|
||||
transition: grid-template-rows 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.sb-section--folded .sb-section__body {
|
||||
grid-template-rows: 0fr;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sb-section__body-inner {
|
||||
overflow: hidden;
|
||||
margin-left: 1.375rem;
|
||||
padding-left: 0.375rem;
|
||||
position: relative;
|
||||
transition: opacity 0.24s ease;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
@@ -571,10 +488,6 @@ interface NavSectionGroup {
|
||||
}
|
||||
}
|
||||
|
||||
.sb-section--folded .sb-section__body-inner {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
Footer
|
||||
================================================================ */
|
||||
@@ -780,7 +693,7 @@ export class AppSidebarComponent implements AfterViewInit {
|
||||
StellaOpsScopes.RELEASE_WRITE,
|
||||
StellaOpsScopes.RELEASE_PUBLISH,
|
||||
],
|
||||
},
|
||||
},
|
||||
{ id: 'rel-hotfix-list', label: 'Hotfixes', route: '/releases/hotfixes', icon: 'zap' },
|
||||
{ id: 'rel-envs', label: 'Environments', route: '/releases/environments', icon: 'globe' },
|
||||
{
|
||||
|
||||
@@ -997,6 +997,7 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
|
||||
readonly placeholderIndex = signal(0);
|
||||
readonly searchResponse = signal<UnifiedSearchResponse | null>(null);
|
||||
readonly suggestionViability = signal<SearchSuggestionViabilityResponse | null>(null);
|
||||
readonly suggestionViabilityStatus = signal<'idle' | 'ready' | 'unavailable'>('idle');
|
||||
readonly recentSearches = signal<string[]>([]);
|
||||
readonly suppressedStarterQueries = signal<string[]>([]);
|
||||
readonly expandedCardKey = signal<string | null>(null);
|
||||
@@ -1243,6 +1244,29 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
}
|
||||
|
||||
if (this.isSearchEnvironmentLikelyUnready(response)) {
|
||||
return {
|
||||
status: 'insufficient',
|
||||
eyebrow,
|
||||
title: this.t('ui.search.answer.title.unready', 'Search needs live data'),
|
||||
summary: this.t(
|
||||
'ui.search.answer.summary.unready',
|
||||
'The live search service accepted "{query}" but returned zero indexed matches. This usually means search ingestion or index rebuild is not ready for this environment.',
|
||||
{ query },
|
||||
),
|
||||
evidence: this.t(
|
||||
'ui.search.answer.evidence.unready',
|
||||
'Search suggestion verification is also unavailable on this environment, so starter queries cannot be trusted until the search APIs are fully configured.',
|
||||
),
|
||||
citations: [],
|
||||
questionLabel: '',
|
||||
questions: [],
|
||||
guidanceLabel: null,
|
||||
guidance: [],
|
||||
nextSearches: [],
|
||||
};
|
||||
}
|
||||
|
||||
const clarifyingQuestions = this.clarifyingQuestions();
|
||||
if (clarifyingQuestions.length > 0) {
|
||||
return {
|
||||
@@ -2106,6 +2130,7 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
|
||||
|
||||
if (queries.length === 0) {
|
||||
this.suggestionViability.set(null);
|
||||
this.suggestionViabilityStatus.set('idle');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2113,6 +2138,7 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((response) => {
|
||||
this.suggestionViability.set(response);
|
||||
this.suggestionViabilityStatus.set(response ? 'ready' : 'unavailable');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2399,6 +2425,18 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
|
||||
|| (response.synthesis?.sourceCount ?? 0) > 0;
|
||||
}
|
||||
|
||||
private hasZeroIndexedMatches(response: UnifiedSearchResponse): boolean {
|
||||
return !this.hasSearchEvidence(response)
|
||||
&& (response.diagnostics?.ftsMatches ?? 0) === 0
|
||||
&& (response.diagnostics?.vectorMatches ?? 0) === 0
|
||||
&& (response.diagnostics?.entityCardCount ?? 0) === 0;
|
||||
}
|
||||
|
||||
private isSearchEnvironmentLikelyUnready(response: UnifiedSearchResponse): boolean {
|
||||
return this.suggestionViabilityStatus() === 'unavailable'
|
||||
&& this.hasZeroIndexedMatches(response);
|
||||
}
|
||||
|
||||
private reconcileSuggestedExecution(response: UnifiedSearchResponse): void {
|
||||
const pending = this.pendingSuggestedExecution;
|
||||
if (!pending) {
|
||||
|
||||
@@ -818,6 +818,25 @@ describe('GlobalSearchComponent', () => {
|
||||
expect(guidanceItems).toContain('Add the part of the finding that matters most right now.');
|
||||
});
|
||||
|
||||
it('renders a search-readiness answer instead of clarify guidance when viability preflight is unavailable', async () => {
|
||||
searchClient.evaluateSuggestions.and.returnValue(of(null));
|
||||
|
||||
component.onFocus();
|
||||
fixture.detectChanges();
|
||||
component.onQueryChange('database connectivity');
|
||||
await waitForDebounce();
|
||||
fixture.detectChanges();
|
||||
|
||||
const answerPanel = fixture.nativeElement.querySelector('[data-answer-status="insufficient"]') as HTMLElement | null;
|
||||
const guidanceItems = fixture.nativeElement.querySelectorAll('[data-answer-guidance="clarify"]');
|
||||
|
||||
expect(answerPanel).not.toBeNull();
|
||||
expect(answerPanel?.textContent).toContain('Search needs live data');
|
||||
expect(answerPanel?.textContent).toContain('returned zero indexed matches');
|
||||
expect(answerPanel?.textContent).toContain('suggestion verification is also unavailable');
|
||||
expect(guidanceItems.length).toBe(0);
|
||||
});
|
||||
|
||||
it('does not hard-filter search requests to the current route scope', async () => {
|
||||
ambientContext.buildContextFilter.and.returnValue({ domains: ['findings'] } as any);
|
||||
|
||||
|
||||
@@ -362,6 +362,34 @@ test.describe('Unified Search - Experience Quality UX', () => {
|
||||
await expect(page.locator('app-global-search input[type="text"]')).toHaveValue('mystery release blocker');
|
||||
});
|
||||
|
||||
test('shows search-readiness guidance instead of blaming the query when the live search corpus is unavailable', async ({ page }) => {
|
||||
await page.unroute('**/api/v1/search/suggestions/evaluate');
|
||||
await page.route('**/api/v1/search/suggestions/evaluate', async (route) =>
|
||||
route.fulfill({
|
||||
status: 404,
|
||||
body: '',
|
||||
}),
|
||||
);
|
||||
await mockSearchResponses(page, () => emptyResponse('database connectivity'));
|
||||
|
||||
await page.goto('/releases/versions');
|
||||
await expect(page.locator('aside.sidebar')).toBeVisible({ timeout: 15_000 });
|
||||
|
||||
const searchInput = page.locator('app-global-search input[type="text"]');
|
||||
await searchInput.focus();
|
||||
await waitForResults(page);
|
||||
await searchInput.fill('database connectivity');
|
||||
await searchInput.press('Enter');
|
||||
await waitForResults(page);
|
||||
|
||||
const answerPanel = page.locator('[data-answer-status="insufficient"]');
|
||||
await expect(answerPanel).toBeVisible();
|
||||
await expect(answerPanel).toContainText(/search needs live data/i);
|
||||
await expect(answerPanel).toContainText(/returned zero indexed matches/i);
|
||||
await expect(answerPanel).toContainText(/suggestion verification is also unavailable/i);
|
||||
await expect(page.locator('[data-answer-guidance="clarify"]')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('uses backend answer framing and shows overflow as secondary results without manual filters', async ({ page }) => {
|
||||
await mockSearchResponses(page, (query) =>
|
||||
query.includes('critical findings')
|
||||
|
||||
16
src/Web/StellaOps.Web/vitest.codex.config.ts
Normal file
16
src/Web/StellaOps.Web/vitest.codex.config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
pool: 'threads',
|
||||
poolOptions: {
|
||||
threads: {
|
||||
singleThread: true,
|
||||
},
|
||||
},
|
||||
fileParallelism: false,
|
||||
isolate: false,
|
||||
maxWorkers: 1,
|
||||
minWorkers: 1,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user