feat(fleet): card-only UI with progressive load and restart ops

Drop the redundant advanced table so fleet stays resource-first cards.
Keep multi-select batch service/system restart via prepare→execute, card
restarts, overview system ops, and progressive fleet loading.
This commit is contained in:
chick
2026-07-21 22:56:55 +08:00
parent ebed4c1969
commit 9ea8021cce
20 changed files with 1207 additions and 346 deletions
+65 -3
View File
@@ -1,6 +1,6 @@
// @vitest-environment jsdom
import { cleanup, render, screen, within } from '@testing-library/react';
import { afterEach, describe, expect, it } from 'vitest';
import { cleanup, fireEvent, render, screen, within } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { FleetPage, type FleetSnapshot } from './fleet-page.js';
@@ -11,13 +11,13 @@ const snapshot: FleetSnapshot = {
name: 'Alpha modem',
url: 'http://192.168.1.2',
tags: [],
revision: 3,
},
],
statuses: new Map([
[
'alpha',
{
instanceId: 'alpha',
reachable: true,
authenticated: true,
summary: { freshness: 'fresh', resources: { cpuPercent: 24, memoryPercent: 51 } },
@@ -52,3 +52,65 @@ describe('FleetPage card navigation', () => {
expect(within(card).getByRole('group', { name: '实例管理操作' })).toBeTruthy();
});
});
describe('FleetPage batch and restart actions', () => {
it('exposes card restart controls and batch restart entry for selected instances', async () => {
const prepare = vi.fn(async () => ({
id: 'prep-1',
status: 'prepared',
operationId: 'postServiceRestart',
risk: 'R3',
expiresAt: '2030-01-01T00:00:00.000Z',
confirmationPrompt: 'Confirm restart',
targetCount: 1,
}));
const execute = vi.fn(async () => ({
id: 'job-1',
operationId: 'postServiceRestart',
status: 'succeeded',
rootJobId: 'job-1',
items: [{ id: 'item-1', targetId: 'alpha', state: 'succeeded' }],
attempts: [],
createdAt: '2029-01-01T00:00:00.000Z',
}));
const list = vi.fn(async () => ({
items: [
{
operationId: 'postServiceRestart',
title: 'Restart Service',
risk: 'R3',
capability: 'job',
batchable: false,
parameterSchemaId: 'simadmin.58e2204.postServiceRestart.parameters.v1',
},
{
operationId: 'postSystemReboot',
title: 'Reboot System',
risk: 'R3',
capability: 'job',
batchable: false,
parameterSchemaId: 'simadmin.58e2204.postSystemReboot.parameters.v1',
},
],
page: { page: 1, pageSize: 100, total: 2 },
}));
vi.stubGlobal('confirm', () => true);
render(
<FleetPage
initialData={snapshot}
operationClient={{ list, prepare, execute } as never}
/>,
);
const card = screen.getByRole('article', { name: 'Alpha modem 实例概览' });
expect(within(card).getByRole('button', { name: '重启服务 Alpha modem' })).toBeTruthy();
expect(within(card).getByRole('button', { name: '系统重启 Alpha modem' })).toBeTruthy();
fireEvent.click(within(card).getByRole('checkbox', { name: '选择 Alpha modem' }));
expect(screen.getByText(/已选择 1 项/).textContent).toMatch(/已选择 1 项/);
fireEvent.click(screen.getByRole('button', { name: '批量操作' }));
const batch = await screen.findByRole('region', { name: '批量操作入口' });
expect(batch.textContent).toMatch(/已选择 1 项/);
fireEvent.click(screen.getByRole('button', { name: '批量重启服务' }));
await vi.waitFor(() => expect(prepare).toHaveBeenCalled());
expect(execute).toHaveBeenCalledWith('prep-1');
});
});