feat(web): prioritize SMS operations workspace

This commit is contained in:
chick
2026-07-19 10:30:52 +08:00
parent 0112e3320a
commit f7d69a0fa7
10 changed files with 532 additions and 68 deletions
+41 -4
View File
@@ -7,6 +7,7 @@ import { AppShell, type InstanceContext } from './app-shell.js';
import type { AuditDataSource } from './audit/audit-page.js';
import type { EventStreamClient } from './events/event-stream-client.js';
import { type FleetDataSource, type FleetSnapshot } from './fleet/fleet-page.js';
import type { FleetMessagesDataSource } from './fleet/fleet-messages-api-data-source.js';
import type { InstanceDataSource } from './instances/instance-api-data-source.js';
import type { JobsDataSource } from './jobs/jobs-page.js';
@@ -116,10 +117,27 @@ describe('React AppShell and Fleet vertical slice', () => {
delete: remove,
};
const fleetMessagesDataSource: FleetMessagesDataSource = {
load: vi.fn(async (instanceId) =>
instanceId === 'bravo'
? {
latest: {
id: 'sms-1',
direction: 'incoming',
phoneNumber: '13900139000',
content: '这是一条用于聚合页展示的最新短信内容',
timestamp: '2026-07-19T08:30:00.000Z',
},
}
: {},
),
};
render(
<AppShell
pathname="/fleet"
fleetDataSource={source(async () => snapshot)}
fleetMessagesDataSource={fleetMessagesDataSource}
instanceDataSource={instanceDataSource}
/>,
);
@@ -139,8 +157,13 @@ describe('React AppShell and Fleet vertical slice', () => {
expect(within(card).getByText('63.2%')).toBeTruthy();
expect(within(card).getByText('46.7 °C')).toBeTruthy();
expect(within(card).getByText('13800138000')).toBeTruthy();
expect(within(card).getByRole('link', { name: '管理 Bravo' }).getAttribute('href')).toBe(
'/instances/bravo/overview',
expect(await within(card).findByText('收到')).toBeTruthy();
expect(within(card).getByText('13900139000')).toBeTruthy();
expect(within(card).getByText(/这是一条用于聚合页展示/)).toBeTruthy();
expect(within(card).getByText(/2026/)).toBeTruthy();
expect(within(card).queryByText('能力未知')).toBeNull();
expect(within(card).getByRole('link', { name: '查看 Bravo 的短信' }).getAttribute('href')).toBe(
'/instances/bravo/messages',
);
expect(within(card).getByRole('link', { name: '编辑 Bravo' }).getAttribute('href')).toBe(
'/settings/instances/bravo',
@@ -154,6 +177,20 @@ describe('React AppShell and Fleet vertical slice', () => {
expect(within(card).getByRole('status').textContent).toContain('删除请求已提交');
});
it('keeps message read failures separate from instance reachability and reports each once', async () => {
const messages: FleetMessagesDataSource = { load: vi.fn().mockRejectedValue(new Error('no')) };
render(
<AppShell
pathname="/fleet"
fleetDataSource={source(async () => snapshot)}
fleetMessagesDataSource={messages}
/>,
);
const bravo = await screen.findByRole('article', { name: 'Bravo 实例概览' });
expect(await within(bravo).findAllByText('短信暂不可用')).toHaveLength(1);
expect(within(bravo).getByText('需要认证')).toBeTruthy();
});
it('keeps Jobs and Audit routes compatible without advertising them in global navigation', async () => {
const jobsDataSource: JobsDataSource = { load: vi.fn().mockResolvedValue(emptyPage) };
const { rerender } = render(
@@ -204,7 +241,7 @@ describe('React AppShell and Fleet vertical slice', () => {
expect(screen.getByRole('status').textContent).toContain('正在加载实例');
expect(await screen.findByText('Bravo')).toBeTruthy();
expect(screen.getByRole('heading', { name: '概览' })).toBeTruthy();
expect(screen.getByRole('heading', { name: '设备信息' })).toBeTruthy();
expect(screen.getByRole('link', { name: '编辑实例' }).getAttribute('href')).toBe(
'/settings/instances/bravo',
);
@@ -315,7 +352,7 @@ describe('React AppShell and Fleet vertical slice', () => {
const { rerender } = render(
<AppShell pathname="/instances/owner/messages" instance={instance} />,
);
expect(screen.getByRole('heading', { name: '消息' })).toBeTruthy();
expect(screen.getByRole('heading', { name: '短信' })).toBeTruthy();
expect(screen.getByText('Owner modem')).toBeTruthy();
expect(screen.getByRole('link', { name: '打开源站' }).getAttribute('href')).toBe(
'https://owner.example',