feat(web): rebuild fleet page with Hub-style identity guard and context actions

- Surface device identity state, carrier details and upstream link health.

- Add fleet-level identity monitoring and restart/baseband context actions.

- Apply consistent notification scoping across fleet views.
This commit is contained in:
chick
2026-09-07 00:45:28 +08:00
parent 635527dd26
commit 864e1bd90c
16 changed files with 1596 additions and 90 deletions
@@ -265,4 +265,36 @@ describe('Fleet heartbeat connection state', () => {
expect(partials[0]).toMatchObject({ probed: true, reachable: false });
expect(partials.at(-1)).toMatchObject({ probed: true, reachable: false });
});
it('carries the identity guard verdict onto the row, in both passes', async () => {
const fetcher = vi.fn(async () => {
const base = overviewWith({ probed: true, reachable: true, authenticated: true });
const response = await base();
const body = await response.json();
body.items[0].identity = { tracked: true, status: 'pending', reasons: ['imei_claimed'] };
return new Response(JSON.stringify(body), {
status: 200,
headers: { 'content-type': 'application/json' },
});
});
const partials: unknown[] = [];
const snapshot = await createFleetApiDataSource(fetcher as unknown as typeof fetch).load(
undefined,
(value) => partials.push(value.statuses.get('alpha')),
);
expect(partials[0]).toMatchObject({ identity: { status: 'pending' } });
expect(snapshot.statuses.get('alpha')?.identity).toEqual({
tracked: true,
status: 'pending',
reasons: ['imei_claimed'],
});
});
it('leaves the row unbadged for a server without the identity guard', async () => {
const snapshot = await createFleetApiDataSource(
overviewWith(undefined) as unknown as typeof fetch,
).load();
expect(snapshot.statuses.get('alpha')?.identity).toBeUndefined();
});
});