refactor(ui): converge semi history workspace
This commit is contained in:
@@ -54,6 +54,12 @@ function renderPage(initialEntry = '/history?keywords=OLDVIN&dateFrom=2026-07-16
|
|||||||
return { ...view, client };
|
return { ...view, client };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openDesktopTool(name: RegExp | string) {
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: '打开历史数据更多操作' }));
|
||||||
|
const item = await screen.findByRole('menuitem', { name });
|
||||||
|
fireEvent.click(item);
|
||||||
|
}
|
||||||
|
|
||||||
test('renders protocol timestamps in Asia/Shanghai while preserving local values', () => {
|
test('renders protocol timestamps in Asia/Shanghai while preserving local values', () => {
|
||||||
expect(formatHistoryDateTime('2026-07-18T02:33:00Z')).toBe('2026-07-18 10:33:00');
|
expect(formatHistoryDateTime('2026-07-18T02:33:00Z')).toBe('2026-07-18 10:33:00');
|
||||||
expect(formatHistoryDateTime('2026-07-18T02:33:00+08:00')).toBe('2026-07-18 02:33:00');
|
expect(formatHistoryDateTime('2026-07-18T02:33:00+08:00')).toBe('2026-07-18 02:33:00');
|
||||||
@@ -141,12 +147,12 @@ test('clears stale rows, charts, and evidence as soon as the history scope chang
|
|||||||
expect(view.container.querySelector('input[type="datetime-local"]')).not.toBeInTheDocument();
|
expect(view.container.querySelector('input[type="datetime-local"]')).not.toBeInTheDocument();
|
||||||
expect(view.container.querySelector('.v2-history-summary-rail')).toHaveClass('v2-workspace-metric-rail', 'is-queue');
|
expect(view.container.querySelector('.v2-history-summary-rail')).toHaveClass('v2-workspace-metric-rail', 'is-queue');
|
||||||
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list')).toHaveAttribute('aria-label', '历史数据查询统计信息');
|
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list')).toHaveAttribute('aria-label', '历史数据查询统计信息');
|
||||||
expect(view.container.querySelectorAll('.v2-history-summary-rail .v2-workspace-metric-list > span')).toHaveLength(4);
|
expect(view.container.querySelectorAll('.v2-history-summary-rail .v2-workspace-metric-list > span')).toHaveLength(3);
|
||||||
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list > span.is-primary')).toHaveTextContent('结果行数1当前范围');
|
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list > span.is-primary')).toHaveTextContent('结果行数1当前范围');
|
||||||
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list')).toHaveTextContent('车辆数1辆1 个车辆标识');
|
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list')).toHaveTextContent('车辆数1辆1 个车辆标识');
|
||||||
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list')).toHaveTextContent('数据来源1路JT808');
|
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list')).toHaveTextContent('数据来源1路JT808');
|
||||||
expect(view.container.querySelector('.v2-history-summary-rail .v2-workspace-metric-list')).toHaveTextContent('查询耗时12ms1 / 1 个业务字段');
|
|
||||||
expect(screen.getByText('1 / 1 字段').closest('.semi-tag')).toBeInTheDocument();
|
expect(screen.getByText('1 / 1 字段').closest('.semi-tag')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('查询 12 ms')).toHaveClass('v2-history-query-duration');
|
||||||
expect(view.container.querySelector('.v2-history-result-actions.v2-workspace-panel-actions')).toBeInTheDocument();
|
expect(view.container.querySelector('.v2-history-result-actions.v2-workspace-panel-actions')).toBeInTheDocument();
|
||||||
expect(view.container.querySelector('.v2-history-evidence')).not.toBeInTheDocument();
|
expect(view.container.querySelector('.v2-history-evidence')).not.toBeInTheDocument();
|
||||||
expect(view.container.querySelector('.v2-history-workspace')).not.toHaveClass('is-inspector-open');
|
expect(view.container.querySelector('.v2-history-workspace')).not.toHaveClass('is-inspector-open');
|
||||||
@@ -331,7 +337,8 @@ test('releases export job state immediately after leaving the history page', asy
|
|||||||
mocks.historyExports.mockResolvedValue([{ id: 'export-running', name: '运行中导出', status: 'running', progress: 30, format: 'csv', category: 'location', keywords: ['OLDVIN'], rowCount: 0, totalRows: 100, processedRows: 30, fileSizeBytes: 0, createdAt: '2026-07-16T04:00:00Z', updatedAt: '2026-07-16T04:00:01Z', evidence: 'test export' }]);
|
mocks.historyExports.mockResolvedValue([{ id: 'export-running', name: '运行中导出', status: 'running', progress: 30, format: 'csv', category: 'location', keywords: ['OLDVIN'], rowCount: 0, totalRows: 100, processedRows: 30, fileSizeBytes: 0, createdAt: '2026-07-16T04:00:00Z', updatedAt: '2026-07-16T04:00:01Z', evidence: 'test export' }]);
|
||||||
|
|
||||||
const { client, unmount } = renderPage();
|
const { client, unmount } = renderPage();
|
||||||
fireEvent.click(await screen.findByRole('button', { name: '查看导出任务' }));
|
await screen.findByText('旧车牌');
|
||||||
|
await openDesktopTool(/导出任务/);
|
||||||
expect(await screen.findByText('运行中导出')).toBeInTheDocument();
|
expect(await screen.findByText('运行中导出')).toBeInTheDocument();
|
||||||
expect(client.getQueryCache().find({ queryKey: ['history-exports'] })).toBeDefined();
|
expect(client.getQueryCache().find({ queryKey: ['history-exports'] })).toBeDefined();
|
||||||
|
|
||||||
@@ -339,6 +346,25 @@ test('releases export job state immediately after leaving the history page', asy
|
|||||||
await waitFor(() => expect(client.getQueryCache().find({ queryKey: ['history-exports'] })).toBeUndefined());
|
await waitFor(() => expect(client.getQueryCache().find({ queryKey: ['history-exports'] })).toBeUndefined());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('keeps low-frequency desktop table controls in one working tools menu', async () => {
|
||||||
|
mocks.historyMetricCatalog.mockResolvedValue({ categories: [{ key: 'location', label: '位置数据' }], metrics: [metric] });
|
||||||
|
mocks.historyData.mockResolvedValue(historyData('OLDVIN', '旧车牌', 'old-as-of'));
|
||||||
|
mocks.historySeries.mockResolvedValue(historySeries('OLDVIN', '旧车牌', 'old-as-of'));
|
||||||
|
mocks.historyExports.mockResolvedValue([]);
|
||||||
|
const view = renderPage();
|
||||||
|
|
||||||
|
await screen.findByText('旧车牌');
|
||||||
|
expect(view.container.querySelector('.v2-history-table-card')).toHaveClass('is-compact');
|
||||||
|
await openDesktopTool(/切换为舒适密度/);
|
||||||
|
expect(view.container.querySelector('.v2-history-table-card')).toHaveClass('is-comfortable');
|
||||||
|
await openDesktopTool(/切换为紧凑密度/);
|
||||||
|
expect(view.container.querySelector('.v2-history-table-card')).toHaveClass('is-compact');
|
||||||
|
|
||||||
|
const historyRequests = mocks.historyData.mock.calls.length;
|
||||||
|
await openDesktopTool(/刷新数据/);
|
||||||
|
await waitFor(() => expect(mocks.historyData.mock.calls.length).toBeGreaterThan(historyRequests));
|
||||||
|
});
|
||||||
|
|
||||||
test('opens a working column visibility panel and preserves non-hideable identity columns', async () => {
|
test('opens a working column visibility panel and preserves non-hideable identity columns', async () => {
|
||||||
const data = historyData('OLDVIN', '旧车牌', 'old-as-of');
|
const data = historyData('OLDVIN', '旧车牌', 'old-as-of');
|
||||||
data.columns = [metric, optionalMetric];
|
data.columns = [metric, optionalMetric];
|
||||||
@@ -409,7 +435,8 @@ test('shows only the authenticated customer export workspace with owner and scop
|
|||||||
}]);
|
}]);
|
||||||
renderPage();
|
renderPage();
|
||||||
|
|
||||||
fireEvent.click(await screen.findByRole('button', { name: '查看导出任务' }));
|
await screen.findByText('旧车牌');
|
||||||
|
await openDesktopTool(/导出任务/);
|
||||||
expect(await screen.findByText(/customer-a · 1 辆/)).toBeInTheDocument();
|
expect(await screen.findByText(/customer-a · 1 辆/)).toBeInTheDocument();
|
||||||
expect(screen.getByRole('dialog', { name: '历史数据导出任务' })).toBeInTheDocument();
|
expect(screen.getByRole('dialog', { name: '历史数据导出任务' })).toBeInTheDocument();
|
||||||
expect(screen.getByRole('list', { name: '历史数据导出任务摘要' })).toHaveTextContent('生成中0排队与执行可下载1已完成任务需处理0失败任务');
|
expect(screen.getByRole('list', { name: '历史数据导出任务摘要' })).toHaveTextContent('生成中0排队与执行可下载1已完成任务需处理0失败任务');
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMutation, useQuery, useQueryClient, type UseQueryResult } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient, type UseQueryResult } from '@tanstack/react-query';
|
||||||
import { IconCalendar, IconChevronRight, IconClose, IconDownload, IconMapPin, IconRefresh, IconSearch, IconSetting } from '@douyinfe/semi-icons';
|
import { IconCalendar, IconChevronRight, IconClose, IconDownload, IconMapPin, IconMore, IconRefresh, IconSearch, IconSetting } from '@douyinfe/semi-icons';
|
||||||
import { Button, Card, CardGroup, Checkbox, Descriptions, Dropdown, Empty, Input, Progress, Select, Spin, Table, Tag, Typography } from '@douyinfe/semi-ui';
|
import { Button, Card, CardGroup, Checkbox, Descriptions, Dropdown, Empty, Input, Progress, Select, Spin, Table, Tag, Typography } from '@douyinfe/semi-ui';
|
||||||
import { FormEvent, KeyboardEvent, useCallback, useEffect, useMemo, useState } from 'react';
|
import { FormEvent, KeyboardEvent, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
@@ -370,7 +370,7 @@ export default function HistoryPage() {
|
|||||||
const [trendExpanded, setTrendExpanded] = useState(false);
|
const [trendExpanded, setTrendExpanded] = useState(false);
|
||||||
const [filtersCollapsed, setFiltersCollapsed] = useState(true);
|
const [filtersCollapsed, setFiltersCollapsed] = useState(true);
|
||||||
const [exportJobsOpen, setExportJobsOpen] = useState(false);
|
const [exportJobsOpen, setExportJobsOpen] = useState(false);
|
||||||
const [mobileToolsOpen, setMobileToolsOpen] = useState(false);
|
const [toolsOpen, setToolsOpen] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!mobileLayout) return;
|
if (!mobileLayout) return;
|
||||||
setLimit(MOBILE_HISTORY_PAGE_SIZE);
|
setLimit(MOBILE_HISTORY_PAGE_SIZE);
|
||||||
@@ -487,13 +487,6 @@ export default function HistoryPage() {
|
|||||||
note: summarySources,
|
note: summarySources,
|
||||||
tone: 'primary',
|
tone: 'primary',
|
||||||
emphasis: 'secondary'
|
emphasis: 'secondary'
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '查询耗时',
|
|
||||||
value: summaryLoading ? '—' : resultSummary ? <>{resultSummary.queryDurationMs}<i className="v2-history-summary-unit">ms</i></> : '—',
|
|
||||||
note: `${visibleMetrics.length} / ${allMetrics.length} 个业务字段`,
|
|
||||||
tone: 'neutral',
|
|
||||||
emphasis: 'secondary'
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const historyFilterFields = <>
|
const historyFilterFields = <>
|
||||||
@@ -585,31 +578,42 @@ export default function HistoryPage() {
|
|||||||
<WorkspacePanelHeader
|
<WorkspacePanelHeader
|
||||||
title="历史明细"
|
title="历史明细"
|
||||||
description={keywords.length ? `${(result?.total ?? 0).toLocaleString('zh-CN')} 条记录 · ${resultSummary?.vehicleCount ?? 0} 辆车辆 · ${summarySources}` : '选择车辆和时间范围后查询'}
|
description={keywords.length ? `${(result?.total ?? 0).toLocaleString('zh-CN')} 条记录 · ${resultSummary?.vehicleCount ?? 0} 辆车辆 · ${summarySources}` : '选择车辆和时间范围后查询'}
|
||||||
meta={<span className="v2-history-result-meta"><Tag color="blue" type="light" size="small">{visibleMetrics.length} / {allMetrics.length} 字段</Tag>{resultSummary ? <span>{resultSummary.queryDurationMs} ms</span> : null}</span>}
|
meta={<span className="v2-history-result-meta"><Tag color="blue" type="light" size="small">{visibleMetrics.length} / {allMetrics.length} 字段</Tag>{resultSummary ? <span className="v2-history-query-duration">查询 {resultSummary.queryDurationMs} ms</span> : null}</span>}
|
||||||
actionsClassName={`v2-history-result-actions${mobileLayout ? ' is-mobile-actions' : ''}`}
|
actionsClassName={`v2-history-result-actions${mobileLayout ? ' is-mobile-actions' : ''}`}
|
||||||
actions={mobileLayout ? keywords.length ? <>
|
actions={mobileLayout ? keywords.length ? <>
|
||||||
<Button className={`v2-history-table-trend v2-workspace-mobile-tool-button is-muted${trendExpanded ? ' is-expanded' : ''}`} theme="light" aria-label={trendExpanded ? '收起趋势' : '展开趋势'} aria-expanded={trendExpanded} icon={<IconChevronRight />} onClick={() => setTrendExpanded((value) => !value)}>{trendExpanded ? '收起' : '趋势'}</Button>
|
<Button className={`v2-history-table-trend v2-workspace-mobile-tool-button is-muted${trendExpanded ? ' is-expanded' : ''}`} theme="light" aria-label={trendExpanded ? '收起趋势' : '展开趋势'} aria-expanded={trendExpanded} icon={<IconChevronRight />} onClick={() => setTrendExpanded((value) => !value)}>{trendExpanded ? '收起' : '趋势'}</Button>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger="click"
|
trigger="click"
|
||||||
position="bottomRight"
|
position="bottomRight"
|
||||||
visible={mobileToolsOpen}
|
visible={toolsOpen}
|
||||||
onVisibleChange={setMobileToolsOpen}
|
onVisibleChange={setToolsOpen}
|
||||||
contentClassName="v2-workspace-mobile-tools-menu"
|
contentClassName="v2-workspace-mobile-tools-menu"
|
||||||
render={<Dropdown.Menu>
|
render={<Dropdown.Menu>
|
||||||
<Dropdown.Item icon={<IconSetting />} onClick={() => { setMobileToolsOpen(false); setColumnSettingsOpen(true); }}>字段设置</Dropdown.Item>
|
<Dropdown.Item icon={<IconSetting />} onClick={() => { setToolsOpen(false); setColumnSettingsOpen(true); }}>字段设置</Dropdown.Item>
|
||||||
{exportAllowed ? <Dropdown.Item icon={<IconDownload />} onClick={() => { setMobileToolsOpen(false); setExportJobsOpen(true); }}>导出任务</Dropdown.Item> : null}
|
{exportAllowed ? <Dropdown.Item icon={<IconDownload />} onClick={() => { setToolsOpen(false); setExportJobsOpen(true); }}>导出任务</Dropdown.Item> : null}
|
||||||
<Dropdown.Item icon={<IconRefresh />} onClick={() => { setMobileToolsOpen(false); void dataQuery.refetch(); }}>刷新数据</Dropdown.Item>
|
<Dropdown.Item icon={<IconRefresh />} onClick={() => { setToolsOpen(false); void dataQuery.refetch(); }}>刷新数据</Dropdown.Item>
|
||||||
</Dropdown.Menu>}
|
</Dropdown.Menu>}
|
||||||
>
|
>
|
||||||
<Button className="v2-workspace-mobile-tool-button is-muted" theme="light" aria-label="打开历史数据工具" aria-haspopup="menu" aria-expanded={mobileToolsOpen} icon={<IconSetting />}>工具</Button>
|
<Button className="v2-workspace-mobile-tool-button is-muted" theme="light" aria-label="打开历史数据工具" aria-haspopup="menu" aria-expanded={toolsOpen} icon={<IconMore />}>工具</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</> : null : <>
|
</> : null : <>
|
||||||
<Button className={`v2-history-table-trend${trendExpanded ? ' is-expanded' : ''}`} theme="borderless" aria-label={trendExpanded ? '收起趋势' : '展开趋势'} aria-expanded={trendExpanded} icon={<IconChevronRight />} onClick={() => setTrendExpanded((value) => !value)}>{trendExpanded ? '收起趋势' : '聚合趋势'}</Button>
|
<Button className={`v2-history-table-trend${trendExpanded ? ' is-expanded' : ''}`} theme="borderless" aria-label={trendExpanded ? '收起趋势' : '展开趋势'} aria-expanded={trendExpanded} icon={<IconChevronRight />} onClick={() => setTrendExpanded((value) => !value)}>{trendExpanded ? '收起' : '趋势'}</Button>
|
||||||
<Button theme="borderless" aria-label="列设置" aria-haspopup="dialog" aria-expanded={columnSettingsOpen} aria-controls="v2-history-column-settings" icon={<IconSetting />} onClick={() => setColumnSettingsOpen((value) => !value)}>列设置</Button>
|
<Button theme="borderless" aria-label="列设置" aria-haspopup="dialog" aria-expanded={columnSettingsOpen} aria-controls="v2-history-column-settings" icon={<IconSetting />} onClick={() => setColumnSettingsOpen((value) => !value)}>字段</Button>
|
||||||
{exportAllowed ? <CreateExportButton disabled={!resultRows.length} request={exportRequest} /> : null}
|
{exportAllowed ? <CreateExportButton disabled={!resultRows.length} request={exportRequest} /> : null}
|
||||||
{exportAllowed ? <Button theme="borderless" aria-label="查看导出任务" aria-haspopup="dialog" aria-expanded={exportJobsOpen} aria-controls="v2-history-export-jobs" icon={<IconDownload />} onClick={() => setExportJobsOpen(true)}>导出任务</Button> : null}
|
<Dropdown
|
||||||
<Select aria-label="表格密度" value={density} onChange={(value) => setDensity(String(value) as typeof density)} optionList={[{ value: 'compact', label: '紧凑' }, { value: 'comfortable', label: '舒适' }]} />
|
trigger="click"
|
||||||
<Button theme="borderless" onClick={() => dataQuery.refetch()} aria-label="刷新历史数据" icon={<IconRefresh />} />
|
position="bottomRight"
|
||||||
|
visible={toolsOpen}
|
||||||
|
onVisibleChange={setToolsOpen}
|
||||||
|
contentClassName="v2-history-tools-menu"
|
||||||
|
render={<Dropdown.Menu>
|
||||||
|
{exportAllowed ? <Dropdown.Item icon={<IconDownload />} onClick={() => { setToolsOpen(false); setExportJobsOpen(true); }}>导出任务</Dropdown.Item> : null}
|
||||||
|
<Dropdown.Item icon={<IconSetting />} onClick={() => { setToolsOpen(false); setDensity((value) => value === 'compact' ? 'comfortable' : 'compact'); }}>{density === 'compact' ? '切换为舒适密度' : '切换为紧凑密度'}</Dropdown.Item>
|
||||||
|
<Dropdown.Item icon={<IconRefresh />} onClick={() => { setToolsOpen(false); void dataQuery.refetch(); }}>刷新数据</Dropdown.Item>
|
||||||
|
</Dropdown.Menu>}
|
||||||
|
>
|
||||||
|
<Button className="v2-history-more-button" theme="borderless" aria-label="打开历史数据更多操作" aria-haspopup="menu" aria-expanded={toolsOpen} icon={<IconMore />}>更多</Button>
|
||||||
|
</Dropdown>
|
||||||
</>}
|
</>}
|
||||||
/>
|
/>
|
||||||
<ColumnVisibilityPanel visible={columnSettingsOpen} metrics={allMetrics} visibleKeys={visibleKeys} onToggle={toggleMetric} onShowAll={() => setVisibleMetrics(allMetrics.map((metric) => metric.key))} onReset={() => setVisibleMetrics(allMetrics.filter((metric) => metric.defaultVisible).map((metric) => metric.key))} onClose={() => setColumnSettingsOpen(false)} />
|
<ColumnVisibilityPanel visible={columnSettingsOpen} metrics={allMetrics} visibleKeys={visibleKeys} onToggle={toggleMetric} onShowAll={() => setVisibleMetrics(allMetrics.map((metric) => metric.key))} onReset={() => setVisibleMetrics(allMetrics.filter((metric) => metric.defaultVisible).map((metric) => metric.key))} onClose={() => setColumnSettingsOpen(false)} />
|
||||||
|
|||||||
@@ -24258,3 +24258,63 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Semi UI history workspace convergence.
|
||||||
|
* Keep high-frequency evidence actions visible and move low-frequency table
|
||||||
|
* controls into one predictable menu so the table remains the primary surface.
|
||||||
|
*/
|
||||||
|
.v2-history-result-meta {
|
||||||
|
gap: 6px;
|
||||||
|
border: 1px solid #e0e8f2;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #f8fafc;
|
||||||
|
padding: 3px 8px 3px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-history-result-meta > .semi-tag {
|
||||||
|
min-height: 20px;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding-inline: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-history-query-duration {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-history-summary-rail .v2-workspace-metric-list {
|
||||||
|
grid-template-columns: 1.05fr .85fr 1.35fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-history-summary-rail .v2-workspace-metric-list > span:last-child > em {
|
||||||
|
color: #718198;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-history-result-actions > .semi-button,
|
||||||
|
.v2-history-result-actions > .semi-dropdown > .semi-button {
|
||||||
|
min-height: 32px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-history-result-actions > .v2-secondary-button {
|
||||||
|
border-color: #d5e3f6;
|
||||||
|
background: #f2f7ff;
|
||||||
|
color: #155fc5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-history-more-button[aria-expanded="true"] {
|
||||||
|
background: #edf4fe;
|
||||||
|
color: #155fc5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-history-tools-menu {
|
||||||
|
min-width: 190px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 680px) {
|
||||||
|
.v2-history-summary-rail .v2-workspace-metric-list {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user