feat(ui): reconnect evidence-thread and persona workspace routes [SPRINT-021]
Mount evidence-thread, auditor-workspace, and developer-workspace routes under canonical /evidence family as drill-in lenses, not standalone shells. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,14 @@
|
||||
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
/**
|
||||
* Evidence Thread Routes
|
||||
*
|
||||
* Mounted under /evidence/threads by evidence.routes.ts (Sprint 021).
|
||||
* Canonical URLs:
|
||||
* /evidence/threads - Thread list
|
||||
* /evidence/threads/:artifactDigest - Thread detail for a specific artifact
|
||||
*/
|
||||
export const EVIDENCE_THREAD_ROUTES: Routes = [
|
||||
{
|
||||
path: '',
|
||||
@@ -11,7 +19,8 @@ export const EVIDENCE_THREAD_ROUTES: Routes = [
|
||||
import('./components/evidence-thread-list/evidence-thread-list.component').then(
|
||||
(m) => m.EvidenceThreadListComponent
|
||||
),
|
||||
title: 'Evidence Threads'
|
||||
title: 'Evidence Threads',
|
||||
data: { breadcrumb: 'Threads' },
|
||||
},
|
||||
{
|
||||
path: ':artifactDigest',
|
||||
@@ -19,6 +28,7 @@ export const EVIDENCE_THREAD_ROUTES: Routes = [
|
||||
import('./components/evidence-thread-view/evidence-thread-view.component').then(
|
||||
(m) => m.EvidenceThreadViewComponent
|
||||
),
|
||||
title: 'Evidence Thread Detail'
|
||||
title: 'Evidence Thread Detail',
|
||||
data: { breadcrumb: 'Thread Detail' },
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/**
|
||||
* Auditor Workspace Routes
|
||||
* Sprint: SPRINT_0127_0001_FE_sbom_vex_persona_views
|
||||
* Updated: Sprint 021 - Mounted under /evidence/workspaces/auditor
|
||||
* Task: FE-PERSONA-05 - Auditor Workspace Layout
|
||||
*
|
||||
* Canonical URL: /evidence/workspaces/auditor/:artifactDigest
|
||||
* Acts as an evidence lens, not a parallel shell.
|
||||
*/
|
||||
|
||||
import { Routes } from '@angular/router';
|
||||
@@ -14,5 +18,6 @@ export const AUDITOR_WORKSPACE_ROUTES: Routes = [
|
||||
(m) => m.AuditorWorkspaceComponent
|
||||
),
|
||||
title: 'Auditor Workspace',
|
||||
data: { breadcrumb: 'Auditor' },
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/**
|
||||
* Developer Workspace Routes
|
||||
* Sprint: SPRINT_0127_0001_FE_sbom_vex_persona_views
|
||||
* Updated: Sprint 021 - Mounted under /evidence/workspaces/developer
|
||||
* Task: FE-PERSONA-04 - Developer Workspace Layout
|
||||
*
|
||||
* Canonical URL: /evidence/workspaces/developer/:artifactDigest
|
||||
* Acts as an evidence lens, not a parallel shell.
|
||||
*/
|
||||
|
||||
import { Routes } from '@angular/router';
|
||||
@@ -13,8 +17,7 @@ export const DEVELOPER_WORKSPACE_ROUTES: Routes = [
|
||||
import('./components/developer-workspace/developer-workspace.component').then(
|
||||
(m) => m.DeveloperWorkspaceComponent
|
||||
),
|
||||
data: {
|
||||
title: 'Developer Workspace',
|
||||
},
|
||||
title: 'Developer Workspace',
|
||||
data: { breadcrumb: 'Developer' },
|
||||
},
|
||||
];
|
||||
|
||||
72
src/Web/StellaOps.Web/src/app/routes/evidence.routes.spec.ts
Normal file
72
src/Web/StellaOps.Web/src/app/routes/evidence.routes.spec.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Evidence Routes - Route structure verification
|
||||
* Sprint 021: FE-UET-004
|
||||
*
|
||||
* Validates that evidence-thread and persona-workspace routes are mounted
|
||||
* under the canonical /evidence route family with correct breadcrumbs and
|
||||
* lazy-loading configuration.
|
||||
*/
|
||||
import { EVIDENCE_ROUTES } from './evidence.routes';
|
||||
|
||||
describe('EVIDENCE_ROUTES', () => {
|
||||
it('should export a non-empty route array', () => {
|
||||
expect(EVIDENCE_ROUTES).toBeDefined();
|
||||
expect(Array.isArray(EVIDENCE_ROUTES)).toBe(true);
|
||||
expect(EVIDENCE_ROUTES.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should mount evidence threads at "threads"', () => {
|
||||
const threadsRoute = EVIDENCE_ROUTES.find((r) => r.path === 'threads');
|
||||
expect(threadsRoute).toBeDefined();
|
||||
expect(threadsRoute!.loadChildren).toBeDefined();
|
||||
expect(threadsRoute!.title).toBe('Evidence Threads');
|
||||
expect(threadsRoute!.data?.['breadcrumb']).toBe('Threads');
|
||||
});
|
||||
|
||||
it('should mount auditor workspace at "workspaces/auditor"', () => {
|
||||
const auditorRoute = EVIDENCE_ROUTES.find((r) => r.path === 'workspaces/auditor');
|
||||
expect(auditorRoute).toBeDefined();
|
||||
expect(auditorRoute!.loadChildren).toBeDefined();
|
||||
expect(auditorRoute!.title).toBe('Auditor Workspace');
|
||||
expect(auditorRoute!.data?.['breadcrumb']).toBe('Auditor Workspace');
|
||||
});
|
||||
|
||||
it('should mount developer workspace at "workspaces/developer"', () => {
|
||||
const devRoute = EVIDENCE_ROUTES.find((r) => r.path === 'workspaces/developer');
|
||||
expect(devRoute).toBeDefined();
|
||||
expect(devRoute!.loadChildren).toBeDefined();
|
||||
expect(devRoute!.title).toBe('Developer Workspace');
|
||||
expect(devRoute!.data?.['breadcrumb']).toBe('Developer Workspace');
|
||||
});
|
||||
|
||||
it('should not introduce a separate top-level persona menu', () => {
|
||||
// All persona routes must be nested under workspaces/, not at root
|
||||
const topLevelPaths = EVIDENCE_ROUTES.map((r) => r.path);
|
||||
expect(topLevelPaths).not.toContain('auditor');
|
||||
expect(topLevelPaths).not.toContain('developer');
|
||||
});
|
||||
|
||||
it('should preserve the canonical evidence overview route', () => {
|
||||
const overviewRoute = EVIDENCE_ROUTES.find((r) => r.path === '' || r.path === 'overview');
|
||||
expect(overviewRoute).toBeDefined();
|
||||
});
|
||||
|
||||
it('should preserve capsules, proofs, exports, and audit-log routes', () => {
|
||||
const paths = EVIDENCE_ROUTES.map((r) => r.path);
|
||||
expect(paths).toContain('capsules');
|
||||
expect(paths).toContain('proofs');
|
||||
expect(paths).toContain('exports');
|
||||
expect(paths).toContain('audit-log');
|
||||
});
|
||||
|
||||
it('should use loadChildren for lazy-loaded thread and workspace routes', () => {
|
||||
const lazyRoutes = ['threads', 'workspaces/auditor', 'workspaces/developer'];
|
||||
for (const path of lazyRoutes) {
|
||||
const route = EVIDENCE_ROUTES.find((r) => r.path === path);
|
||||
expect(route).toBeDefined();
|
||||
expect(typeof route!.loadChildren).toBe('function');
|
||||
// loadComponent should not be set when loadChildren is used
|
||||
expect(route!.loadComponent).toBeUndefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,23 @@
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
/**
|
||||
* Evidence Routes
|
||||
*
|
||||
* Canonical URL contract (Sprint 021):
|
||||
* /evidence - Evidence overview
|
||||
* /evidence/overview - Evidence overview (alias)
|
||||
* /evidence/threads - Evidence thread list
|
||||
* /evidence/threads/:artifactDigest - Evidence thread detail
|
||||
* /evidence/workspaces/auditor/:artifactDigest - Auditor workspace lens
|
||||
* /evidence/workspaces/developer/:artifactDigest - Developer workspace lens
|
||||
* /evidence/capsules - Decision capsule list
|
||||
* /evidence/capsules/:capsuleId - Decision capsule detail
|
||||
* /evidence/verify-replay - Verify & Replay
|
||||
* /evidence/proofs - Proof chains
|
||||
* /evidence/exports - Evidence exports
|
||||
* /evidence/proof-chain - Proof chain (alias)
|
||||
* /evidence/audit-log - Audit log
|
||||
*/
|
||||
export const EVIDENCE_ROUTES: Routes = [
|
||||
{
|
||||
path: '',
|
||||
@@ -19,6 +37,27 @@ export const EVIDENCE_ROUTES: Routes = [
|
||||
(m) => m.EvidenceAuditOverviewComponent,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'threads',
|
||||
title: 'Evidence Threads',
|
||||
data: { breadcrumb: 'Threads' },
|
||||
loadChildren: () =>
|
||||
import('../features/evidence-thread/evidence-thread.routes').then((m) => m.EVIDENCE_THREAD_ROUTES),
|
||||
},
|
||||
{
|
||||
path: 'workspaces/auditor',
|
||||
title: 'Auditor Workspace',
|
||||
data: { breadcrumb: 'Auditor Workspace' },
|
||||
loadChildren: () =>
|
||||
import('../features/workspaces/auditor/auditor-workspace.routes').then((m) => m.AUDITOR_WORKSPACE_ROUTES),
|
||||
},
|
||||
{
|
||||
path: 'workspaces/developer',
|
||||
title: 'Developer Workspace',
|
||||
data: { breadcrumb: 'Developer Workspace' },
|
||||
loadChildren: () =>
|
||||
import('../features/workspaces/developer/developer-workspace.routes').then((m) => m.DEVELOPER_WORKSPACE_ROUTES),
|
||||
},
|
||||
{
|
||||
path: 'capsules',
|
||||
title: 'Decision Capsules',
|
||||
|
||||
Reference in New Issue
Block a user