Restore mission control leaves and alert drilldown return path

This commit is contained in:
master
2026-03-10 15:00:59 +02:00
parent ec22b8ee46
commit 5c10aa7f71
5 changed files with 126 additions and 11 deletions

View File

@@ -55,11 +55,16 @@ function attachRuntimeObservers(page, runtime) {
return;
}
const errorText = request.failure()?.errorText ?? 'unknown';
if (errorText === 'net::ERR_ABORTED') {
return;
}
runtime.requestFailures.push({
page: page.url(),
method: request.method(),
url: request.url(),
error: request.failure()?.errorText ?? 'unknown',
error: errorText,
});
});
@@ -306,7 +311,12 @@ async function main() {
action: 'link:Watchlist alert',
name: 'Identity watchlist alert requires signer review',
expectedPath: '/setup/trust-signing/watchlist/alerts',
expectQuery: { alertId: 'alert-001', tab: 'alerts', scope: 'tenant' },
expectQuery: {
alertId: 'alert-001',
returnTo: '/mission-control/alerts',
scope: 'tenant',
tab: 'alerts',
},
},
{
action: 'link:Waivers expiring',

View File

@@ -0,0 +1,45 @@
import { MISSION_CONTROL_ROUTES } from './mission-control.routes';
function loadedComponentName(
candidate: unknown,
): string {
if (!candidate) {
return '';
}
if (typeof candidate === 'function') {
return candidate.name;
}
if (typeof candidate !== 'object') {
return '';
}
if ('default' in candidate && candidate.default && typeof candidate.default === 'function') {
return candidate.default.name;
}
if ('name' in candidate && typeof candidate.name === 'string') {
return candidate.name;
}
return '';
}
describe('MISSION_CONTROL_ROUTES', () => {
it('keeps alerts and activity as dedicated mission control routes', async () => {
const alertsRoute = MISSION_CONTROL_ROUTES.find((route) => route.path === 'alerts');
const activityRoute = MISSION_CONTROL_ROUTES.find((route) => route.path === 'activity');
expect(alertsRoute?.redirectTo).toBeUndefined();
expect(activityRoute?.redirectTo).toBeUndefined();
expect(alertsRoute?.title).toBe('Mission Alerts');
expect(activityRoute?.title).toBe('Mission Activity');
const alertsComponent = await alertsRoute?.loadComponent?.();
const activityComponent = await activityRoute?.loadComponent?.();
expect(loadedComponentName(alertsComponent)).toContain('MissionAlertsPageComponent');
expect(loadedComponentName(activityComponent)).toContain('MissionActivityPageComponent');
});
});

View File

@@ -1,4 +1,5 @@
import { Routes } from '@angular/router';
import { inject } from '@angular/core';
import { Router, Routes } from '@angular/router';
export const MISSION_CONTROL_ROUTES: Routes = [
{
@@ -15,6 +16,7 @@ export const MISSION_CONTROL_ROUTES: Routes = [
loadComponent: () =>
import('../features/dashboard-v3/dashboard-v3.component').then((m) => m.DashboardV3Component),
},
// Redirects for removed dashboard children
{
path: 'alerts',
title: 'Mission Alerts',
@@ -31,16 +33,24 @@ export const MISSION_CONTROL_ROUTES: Routes = [
},
{
path: 'release-health',
title: 'Release Health',
data: { breadcrumb: 'Release Health' },
loadComponent: () =>
import('../features/topology/environment-posture-page.component').then((m) => m.EnvironmentPosturePageComponent),
pathMatch: 'full',
redirectTo: ({ queryParams, fragment }) => {
const router = inject(Router);
const target = router.parseUrl('/releases/health');
target.queryParams = { ...queryParams };
target.fragment = fragment ?? null;
return target;
},
},
{
path: 'security-posture',
title: 'Security Posture',
data: { breadcrumb: 'Security Posture' },
loadComponent: () =>
import('../features/security-risk/security-risk-overview.component').then((m) => m.SecurityRiskOverviewComponent),
pathMatch: 'full',
redirectTo: ({ queryParams, fragment }) => {
const router = inject(Router);
const target = router.parseUrl('/security/posture');
target.queryParams = { ...queryParams };
target.fragment = fragment ?? null;
return target;
},
},
];