feat(web): protect phone data and polish release UI
This commit is contained in:
@@ -23,7 +23,12 @@ const snapshot: FleetSnapshot = {
|
||||
summary: {
|
||||
version: '1.1.6',
|
||||
freshness: 'fresh',
|
||||
resources: { cpuPercent: 24, memoryPercent: 51, maxTemperatureCelsius: 42 },
|
||||
resources: {
|
||||
cpuPercent: 24,
|
||||
memoryPercent: 51,
|
||||
maxTemperatureCelsius: 42,
|
||||
phoneNumbers: ['+852 5550 0100'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -33,6 +38,95 @@ const snapshot: FleetSnapshot = {
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('FleetPage card navigation', () => {
|
||||
it('masks both phone locations and reveals them only for the selected card', async () => {
|
||||
const privacySnapshot: FleetSnapshot = {
|
||||
instances: [
|
||||
...snapshot.instances,
|
||||
{
|
||||
id: 'beta',
|
||||
name: 'Beta modem',
|
||||
url: 'http://192.168.1.3',
|
||||
tags: [],
|
||||
revision: 1,
|
||||
},
|
||||
],
|
||||
statuses: new Map([
|
||||
...snapshot.statuses,
|
||||
[
|
||||
'beta',
|
||||
{
|
||||
reachable: true,
|
||||
authenticated: true,
|
||||
summary: {
|
||||
version: '1.2.0',
|
||||
freshness: 'fresh' as const,
|
||||
resources: { phoneNumbers: ['13812345678'] },
|
||||
},
|
||||
},
|
||||
],
|
||||
]),
|
||||
};
|
||||
const messagesDataSource = {
|
||||
load: vi.fn(async (instanceId: string) =>
|
||||
instanceId === 'alpha'
|
||||
? {
|
||||
latest: {
|
||||
id: 'sms-1',
|
||||
direction: 'incoming',
|
||||
phoneNumber: '13900139000',
|
||||
content: 'status',
|
||||
timestamp: '2026-07-19T08:30:00.000Z',
|
||||
},
|
||||
}
|
||||
: {},
|
||||
),
|
||||
};
|
||||
|
||||
render(<FleetPage initialData={privacySnapshot} messagesDataSource={messagesDataSource} />);
|
||||
|
||||
const alpha = screen.getByRole('article', { name: 'Alpha modem 实例概览' });
|
||||
const beta = screen.getByRole('article', { name: 'Beta modem 实例概览' });
|
||||
expect(within(alpha).getByText('+852 •••• 0100')).toBeTruthy();
|
||||
expect(within(beta).getByText('138 •••• 5678')).toBeTruthy();
|
||||
expect(await within(alpha).findByText('139 •••• 9000')).toBeTruthy();
|
||||
expect(within(alpha).queryByText('+852 5550 0100')).toBeNull();
|
||||
expect(within(alpha).queryByText('13900139000')).toBeNull();
|
||||
|
||||
const reveal = within(alpha).getByRole('button', { name: '显示 Alpha modem 手机号' });
|
||||
expect(reveal.getAttribute('aria-pressed')).toBe('false');
|
||||
fireEvent.click(reveal);
|
||||
|
||||
expect(within(alpha).getByText('+852 5550 0100')).toBeTruthy();
|
||||
expect(within(alpha).getByText('13900139000')).toBeTruthy();
|
||||
expect(within(beta).getByText('138 •••• 5678')).toBeTruthy();
|
||||
expect(within(beta).queryByText('13812345678')).toBeNull();
|
||||
expect(within(alpha).getByRole('button', { name: '隐藏 Alpha modem 手机号' })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('does not show a privacy toggle when neither phone location has a number', () => {
|
||||
const noNumbers: FleetSnapshot = {
|
||||
...snapshot,
|
||||
statuses: new Map([
|
||||
[
|
||||
'alpha',
|
||||
{
|
||||
...snapshot.statuses.get('alpha')!,
|
||||
summary: {
|
||||
...snapshot.statuses.get('alpha')!.summary,
|
||||
resources: { cpuPercent: 24, memoryPercent: 51 },
|
||||
},
|
||||
},
|
||||
],
|
||||
]),
|
||||
};
|
||||
|
||||
render(<FleetPage initialData={noNumbers} />);
|
||||
|
||||
const card = screen.getByRole('article', { name: 'Alpha modem 实例概览' });
|
||||
expect(within(card).getByText('暂未获取')).toBeTruthy();
|
||||
expect(within(card).queryByRole('button', { name: /手机号/ })).toBeNull();
|
||||
});
|
||||
|
||||
it('makes the whole instance card open its dashboard while ops stay separate and config stays out of the card', () => {
|
||||
render(<FleetPage initialData={snapshot} />);
|
||||
|
||||
@@ -47,6 +141,11 @@ describe('FleetPage card navigation', () => {
|
||||
expect(screen.getByRole('region', { name: '实例状态摘要' }).textContent).toMatch(
|
||||
/实例总数\s*1.*在线\s*1.*需处理\s*0/s,
|
||||
);
|
||||
expect(screen.queryByText('NODE DIRECTORY')).toBeNull();
|
||||
expect(screen.queryByText(/LIVE NODE MATRIX/u)).toBeNull();
|
||||
expect(screen.queryByText('已纳入统一管理')).toBeNull();
|
||||
expect(screen.queryByText('连接与认证正常')).toBeNull();
|
||||
expect(screen.queryByText('离线、认证或未知')).toBeNull();
|
||||
expect(screen.queryByRole('region', { name: '节点资源健康' })).toBeNull();
|
||||
expect(within(card).getByText('SimAdmin 1.1.6')).toBeTruthy();
|
||||
expect(
|
||||
@@ -147,11 +246,12 @@ describe('FleetPage search and filter toolbar', () => {
|
||||
|
||||
const search = screen.getByRole('search', { name: '实例搜索与筛选' });
|
||||
expect(within(search).getByPlaceholderText('搜索名称、ID、标签、源地址…')).toBeTruthy();
|
||||
expect(within(search).getByText(/显示/).textContent).toMatch(/显示\s*1\s*\/\s*1/);
|
||||
expect(within(search).queryByText(/显示/)).toBeNull();
|
||||
expect(document.querySelector('.fleet-result-count')?.textContent).toMatch(/显示\s*1\s*\/\s*1/);
|
||||
|
||||
fireEvent.click(within(search).getByRole('button', { name: /离线/ }));
|
||||
expect(screen.queryByRole('article', { name: 'Alpha modem 实例概览' })).toBeNull();
|
||||
expect(within(search).getByText(/显示/).textContent).toMatch(/显示\s*0\s*\/\s*1/);
|
||||
expect(document.querySelector('.fleet-result-count')?.textContent).toMatch(/显示\s*0\s*\/\s*1/);
|
||||
expect(within(search).getByRole('button', { name: /移除筛选 状态:离线/ })).toBeTruthy();
|
||||
|
||||
fireEvent.change(within(search).getByPlaceholderText('搜索名称、ID、标签、源地址…'), {
|
||||
@@ -161,7 +261,7 @@ describe('FleetPage search and filter toolbar', () => {
|
||||
|
||||
fireEvent.click(within(search).getByRole('button', { name: '清除全部筛选' }));
|
||||
expect(screen.getByRole('article', { name: 'Alpha modem 实例概览' })).toBeTruthy();
|
||||
expect(within(search).getByText(/显示/).textContent).toMatch(/显示\s*1\s*\/\s*1/);
|
||||
expect(document.querySelector('.fleet-result-count')?.textContent).toMatch(/显示\s*1\s*\/\s*1/);
|
||||
});
|
||||
|
||||
it('filters the matrix from the tag group row without moving search out of the sidebar', () => {
|
||||
|
||||
Reference in New Issue
Block a user