feat(web): complete fleet and instance management slices

This commit is contained in:
chick
2026-07-17 17:12:35 +08:00
parent 4093634e13
commit 6e817f380a
15 changed files with 1737 additions and 203 deletions
@@ -23,7 +23,18 @@ const instances: readonly FleetInstance[] = [
const statuses: ReadonlyMap<string, FleetStatus> = new Map([
[
'charlie',
{ reachable: true, authenticated: true, latencyMs: 55, summary: { carrier: 'Acme' } },
{
reachable: true,
authenticated: true,
latencyMs: 55,
summary: {
carrier: 'Acme',
version: '2.4.1',
capabilities: ['sms', 'ussd'],
freshness: 'stale',
anomalies: ['latency spike'],
},
},
],
['alpha', { reachable: false, latencyMs: 8 }],
['bravo', { reachable: true, authenticated: false, latencyMs: 20 }],
@@ -123,4 +134,69 @@ describe('fleet table view model', () => {
buildFleetTableViewModel(instances, statuses, { sort: { column: 'name', direction: 'desc' } });
expect(instances.map((instance) => instance.id)).toEqual(originalOrder);
});
it('derives optional operational metadata from status summary with safe defaults', () => {
const model = buildFleetTableViewModel(instances, statuses);
const charlie = model.rows.find((row) => row.id === 'charlie');
const alpha = model.rows.find((row) => row.id === 'alpha');
expect(charlie).toMatchObject({
version: '2.4.1',
capabilities: ['sms', 'ussd'],
freshness: 'stale',
anomalies: ['latency spike'],
tags: ['west'],
});
expect(alpha).toMatchObject({
version: null,
capabilities: [],
freshness: 'unknown',
anomalies: [],
tags: ['east'],
});
});
it('combines authentication, capability, version, and tag filters', () => {
expect(
buildFleetTableViewModel(instances, statuses, {
auth: 'authenticated',
capability: 'sms',
version: '2.4.1',
tag: 'west',
}).rows.map((row) => row.id),
).toEqual(['charlie']);
expect(
buildFleetTableViewModel(instances, statuses, { auth: 'required' }).rows.map((row) => row.id),
).toEqual(['bravo']);
});
it('sorts metadata columns, including scalar freshness, and paginates after filtering and sorting', () => {
const model = buildFleetTableViewModel(instances, statuses, {
sort: { column: 'version', direction: 'asc' },
page: 2,
pageSize: 2,
});
expect(model.rows.map((row) => row.id)).toEqual(['bravo', 'delta']);
expect(model.filteredCount).toBe(4);
expect(model.page).toBe(2);
expect(model.pageCount).toBe(2);
expect(model.visibleSelection.rowCount).toBe(2);
expect(
buildFleetTableViewModel(instances, statuses, {
sort: { column: 'freshness', direction: 'asc' },
}).rows.map((row) => row.id),
).toEqual(['charlie', 'alpha', 'bravo', 'delta']);
});
it('clamps invalid pages and exposes filter choices from available data', () => {
const model = buildFleetTableViewModel(instances, statuses, { page: 99, pageSize: 3 });
expect(model.page).toBe(2);
expect(model.rows.map((row) => row.id)).toEqual(['delta']);
expect(model.facets).toEqual({
capabilities: ['sms', 'ussd'],
versions: ['2.4.1'],
tags: ['east', 'west'],
});
});
});