diff --git a/vehicle-data-platform/apps/web/src/v2/domain/protocols.test.ts b/vehicle-data-platform/apps/web/src/v2/domain/protocols.test.ts new file mode 100644 index 00000000..6a1041a8 --- /dev/null +++ b/vehicle-data-platform/apps/web/src/v2/domain/protocols.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, test } from 'vitest'; +import { protocolDisplayLabel, protocolSourceLabel } from './protocols'; + +describe('protocol display vocabulary', () => { + test('uses one user-facing label for every supported vehicle protocol', () => { + expect(protocolDisplayLabel('GB32960')).toBe('GB/T 32960'); + expect(protocolDisplayLabel('JT808')).toBe('JT/T 808'); + expect(protocolDisplayLabel('YUTONG_MQTT')).toBe('宇通 MQTT'); + }); + + test('keeps unknown protocols intact and explains qualified sources', () => { + expect(protocolDisplayLabel('CUSTOM')).toBe('CUSTOM'); + expect(protocolSourceLabel('YUTONG_MQTT:canonical')).toBe('宇通 MQTT · canonical'); + expect(protocolSourceLabel('CUSTOM:gateway')).toBe('CUSTOM:gateway'); + }); +}); diff --git a/vehicle-data-platform/apps/web/src/v2/domain/protocols.ts b/vehicle-data-platform/apps/web/src/v2/domain/protocols.ts new file mode 100644 index 00000000..06918d24 --- /dev/null +++ b/vehicle-data-platform/apps/web/src/v2/domain/protocols.ts @@ -0,0 +1,21 @@ +const PROTOCOL_LABELS: Record = { + GB32960: 'GB/T 32960', + JT808: 'JT/T 808', + YUTONG_MQTT: '宇通 MQTT' +}; + +export function protocolDisplayLabel(protocol?: string) { + const normalized = protocol?.trim() ?? ''; + return normalized ? PROTOCOL_LABELS[normalized] ?? normalized : '—'; +} + +export function protocolSourceLabel(source?: string) { + const normalized = source?.trim() ?? ''; + if (!normalized) return ''; + const separator = normalized.indexOf(':'); + if (separator < 0) return protocolDisplayLabel(normalized); + const protocol = normalized.slice(0, separator); + const qualifier = normalized.slice(separator + 1); + const label = protocolDisplayLabel(protocol); + return label === protocol ? normalized : qualifier ? `${label} · ${qualifier}` : label; +} diff --git a/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.test.tsx index 87cec160..07e91207 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.test.tsx @@ -256,7 +256,7 @@ test('switches to a lightweight realtime list and resolves addresses only on dem expect(view.container.querySelector('.v2-monitor-table-panel')).toHaveClass('semi-card'); expect(view.container.querySelector('.v2-monitor-table.semi-table-wrapper')).toBeInTheDocument(); expect(view.container.querySelector('.v2-monitor-table-scroll > table')).not.toBeInTheDocument(); - expect(screen.getByText('覆盖全部授权车辆;实时字段缺失时显示“—”,文字地址按需解析')).toBeInTheDocument(); + expect(screen.getByText('覆盖全部授权车辆;缺失值显示“—”,地址按需解析')).toBeInTheDocument(); expect(await screen.findAllByText('粤A12345')).toHaveLength(1); expect(screen.getAllByText('42')).toHaveLength(1); expect(screen.getAllByText(/18\.6/)).toHaveLength(1); diff --git a/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.tsx index 177d3513..fcd895b0 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.tsx @@ -104,7 +104,7 @@ const MonitorAddressCell = memo(function MonitorAddressCell({ vehicle }: { vehic const moved = Boolean(current && requested && current.key !== requested.key); if (!current) return 暂无实时位置; - if (!requested) return ; + if (!requested) return ; if (addressQuery.isFetching && !addressQuery.data) return 解析中; if (addressQuery.isError) return ; return
{addressQuery.data?.formattedAddress || '暂无地址'}{addressQuery.dataUpdatedAt ? `解析于 ${new Date(addressQuery.dataUpdatedAt).toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit' })}` : ''}{moved ? : null}
; @@ -123,7 +123,7 @@ function MonitorVehicleTable({ rows, total, page, totalPages, limit, loading, mo return {!mobile ?
{loading ?
: null}{!loading && !rows.length ? : null} : null} diff --git a/vehicle-data-platform/apps/web/src/v2/pages/StatisticsPage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/StatisticsPage.test.tsx index bccac7a7..20ddc3ae 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/StatisticsPage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/StatisticsPage.test.tsx @@ -225,7 +225,7 @@ test('supports searching and selecting license plates before querying exact VINs const search = screen.getByRole('textbox', { name: '搜索车牌' }); fireEvent.focus(search); fireEvent.change(search, { target: { value: '粤A12' } }); - const option = await screen.findByRole('option', { name: '粤A12345 LTEST000000000001 GB32960 JT808 选择' }); + const option = await screen.findByRole('option', { name: '粤A12345 LTEST000000000001 GB/T 32960 JT/T 808 选择' }); expect(screen.getAllByRole('option')).toHaveLength(1); fireEvent.click(option); fireEvent.click(screen.getByRole('button', { name: '查询' })); diff --git a/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.test.tsx index 8e925997..c6177c1e 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/TrackPage.test.tsx @@ -161,10 +161,10 @@ test('merges duplicate vehicle sources and keeps the active date shortcut visibl const search = screen.getByRole('textbox', { name: '搜索轨迹车辆' }); fireEvent.focus(search); fireEvent.change(search, { target: { value: '粤A12345' } }); - const option = await screen.findByRole('option', { name: '粤A12345 LTEST000000000001 JT808 GB32960 选择' }); + const option = await screen.findByRole('option', { name: '粤A12345 LTEST000000000001 JT/T 808 GB/T 32960 选择' }); expect(document.querySelectorAll('.v2-track-vehicle-options [role="option"]')).toHaveLength(1); - expect(option).toHaveTextContent('粤A12345LTEST000000000001JT808GB32960选择'); + expect(option).toHaveTextContent('粤A12345LTEST000000000001JT/T 808GB/T 32960选择'); }); test('renders a map-first replay workspace and connects stop, event, and panel interactions', async () => { diff --git a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.test.tsx index 26021c91..39dddf3f 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.test.tsx @@ -87,6 +87,7 @@ test('polls lightweight single-vehicle realtime data and passes its report inter expect(commandCard?.querySelector('.v2-live-grid > div:first-child')).toHaveTextContent('速度'); expect(commandCard?.querySelector('.v2-live-grid > div:nth-child(2)')).toHaveTextContent('SOC'); expect(commandCard?.querySelector('.v2-live-grid > div:nth-child(4)')).toHaveTextContent('当日里程'); + expect(commandCard?.querySelector('.v2-live-grid > div:nth-child(5)')).toHaveTextContent('推荐来源JT/T 808'); expect(screen.getByLabelText('粤A12345 车辆档案')).toHaveFocus(); expect(screen.getByText('扫描 0 帧 · 上海时间 10:00:00')).toBeInTheDocument(); expect(screen.getByRole('heading', { name: '最新上报', level: 5 })).toBeInTheDocument(); @@ -190,7 +191,7 @@ test('shows deduplicated Semi vehicle candidates and opens the selected VIN', as await waitFor(() => expect(vehicles).toHaveBeenCalledTimes(2)); expect(input).toHaveAttribute('aria-expanded', 'true'); expect(screen.getByRole('heading', { name: '匹配车辆', level: 5 })).toBeInTheDocument(); - const option = await screen.findByRole('option', { name: `${initialRealtime.plate} ${initialRealtime.vin} JT808 选择` }); + const option = await screen.findByRole('option', { name: `${initialRealtime.plate} ${initialRealtime.vin} JT/T 808 选择` }); expect(view.container.querySelector('#v2-vehicle-search-options.v2-vehicle-candidate-list')).toBeInTheDocument(); expect(view.container.querySelector('#v2-vehicle-search-options')).toHaveAttribute('aria-busy', 'false'); expect(screen.getAllByRole('option')).toHaveLength(1); @@ -230,7 +231,9 @@ test('defaults to a compact mobile vehicle directory and keeps eight recent vehi const view = render(} />); expect(await screen.findByText('本页 8 辆')).toBeInTheDocument(); - expect(screen.getAllByRole('listitem', { name: /打开 .* 车辆档案/ })).toHaveLength(8); + expect(screen.getAllByRole('listitem')).toHaveLength(8); + expect(screen.getAllByRole('button', { name: /打开 .* 车辆档案/ })).toHaveLength(8); + expect(screen.getAllByText(/GB\/T 32960|JT\/T 808/).length).toBeGreaterThan(0); expect(view.container.querySelector('.v2-vehicle-directory-table')).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-vehicle-query-panel')).toHaveClass('is-mobile-collapsed'); expect(screen.queryByLabelText('查车操作')).not.toBeInTheDocument(); @@ -486,6 +489,7 @@ test('uses compact Semi telemetry evidence cards on mobile', async () => { expect(screen.getByRole('group', { name: '车辆快捷操作' }).querySelectorAll('.semi-button')).toHaveLength(5); expect(screen.getByRole('group', { name: '车辆快捷操作' })).toHaveTextContent('切换车辆轨迹回放历史数据里程查询告警事件'); expect(document.querySelectorAll('.v2-identity-sources .semi-tag')).toHaveLength(3); + expect(document.querySelector('.v2-identity-sources')).toHaveTextContent('GB/T 32960JT/T 808宇通 MQTT'); expect(document.querySelector('.v2-vehicle-command-card .v2-live-grid')).toHaveAttribute('aria-label', '车辆实时指标'); expect(document.querySelectorAll('.v2-vehicle-command-card .v2-live-grid > [role="listitem"]')).toHaveLength(6); }); diff --git a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx index 1848cbae..3d9b6ff0 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx @@ -13,6 +13,7 @@ import { canAdminister, hasMenu } from '../auth/session'; import { LIVE_QUERY_POLICY, QUERY_MEMORY } from '../queryPolicy'; import { formatTelemetryTime, formatTelemetryValue, telemetryQualityLabel } from '../domain/telemetry'; import { formatZhNumber } from '../domain/formatters'; +import { protocolDisplayLabel, protocolSourceLabel } from '../domain/protocols'; import { isValidAMapCoordinate } from '../../integrations/amap'; import { FleetMap } from '../map/FleetMap'; import { InlineError, PageLoading } from '../shared/AsyncState'; @@ -118,7 +119,7 @@ function Archive({ detail, editable, onUpdated }: { detail: VehicleDetail; edita function Events({ detail }: { detail: VehicleDetail }) { const events = [ ...detail.quality.items.slice(0, 3).map((item) => ({ tone: issueTone(item), title: item.severity === 'error' ? '质量异常' : '质量提醒', detail: item.detail, time: item.lastSeen })), - ...detail.sourceStatus.slice(0, 3).map((item) => ({ tone: item.online ? 'success' : 'muted', title: item.online ? '数据上报' : '来源离线', detail: `${item.protocol} · ${item.online ? '当前在线' : '暂无在线数据'}`, time: item.lastSeen })) + ...detail.sourceStatus.slice(0, 3).map((item) => ({ tone: item.online ? 'success' : 'muted', title: item.online ? '数据上报' : '来源离线', detail: `${protocolDisplayLabel(item.protocol)} · ${item.online ? '当前在线' : '暂无在线数据'}`, time: item.lastSeen })) ].slice(0, 5); return {item.protocol}{item.sourceEndpoint || '协议默认来源'}; + return
{protocolDisplayLabel(item.protocol)}{item.sourceEndpoint || '协议默认来源'}
; } function telemetryRowKey(item?: LatestTelemetryValue) { @@ -260,7 +261,6 @@ function TelemetryPanel({ data, pending, error }: { data?: LatestTelemetryRespon .map((key) => ({ key, label: categoryLabels.get(key) ?? key, count: indexed.valuesByProtocolCategory.get(`${activeProtocol}\u0000${key}`)?.length ?? 0 })); const activeCategory = indexed.valuesByProtocolCategory.has(`${activeProtocol}\u0000${selectedCategory}`) ? selectedCategory : categories[0]?.key ?? ''; const visibleMetrics = indexed.valuesByProtocolCategory.get(`${activeProtocol}\u0000${activeCategory}`) ?? []; - const protocolLabel = (protocol: string) => protocol === 'GB32960' ? 'GB/T 32960' : protocol === 'JT808' ? 'JT/T 808' : protocol === 'YUTONG_MQTT' ? '宇通 MQTT' : protocol; const columns = [ { title: '字段 / 协议映射', dataIndex: 'label', width: 260, render: (_: unknown, item: LatestTelemetryValue) => }, { title: '当前值', dataIndex: 'value', width: 170, render: (_: unknown, item: LatestTelemetryValue) => }, @@ -296,11 +296,11 @@ function TelemetryPanel({ data, pending, error }: { data?: LatestTelemetryRespon meta={`${data?.values.length ?? 0} 项`} />
- { setSelectedProtocol(protocol); setSelectedCategory('vehicle'); }} items={indexed.protocols.map((protocol) => ({ key: protocol, label: protocolLabel(protocol), count: (data?.values ?? []).filter((value) => value.protocol === protocol).length }))} /> + { setSelectedProtocol(protocol); setSelectedCategory('vehicle'); }} items={indexed.protocols.map((protocol) => ({ key: protocol, label: protocolDisplayLabel(protocol), count: (data?.values ?? []).filter((value) => value.protocol === protocol).length }))} />
{state} -
来源{indexed.sources.map((source) => {source.protocol})}扫描 {data?.scannedFrames ?? 0} 帧 · 上海时间 {formatTelemetryTime(data?.asOf)}
+
来源{indexed.sources.map((source) => {protocolDisplayLabel(source.protocol)})}扫描 {data?.scannedFrames ?? 0} 帧 · 上海时间 {formatTelemetryTime(data?.asOf)}
VIN{detail.vin})} @@ -484,7 +484,7 @@ function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, tele
SOC{availableMetric(realtime?.socPercent, realtime?.socAvailable)}%剩余电量
总里程推荐口径
当日里程今日累计
-
推荐来源{fmt(realtime?.primaryProtocol)}{realtime?.locationSource || '当前最优来源'}
+
推荐来源{protocolDisplayLabel(realtime?.primaryProtocol)}{protocolSourceLabel(realtime?.locationSource) || '当前最优来源'}
来源状态{realtime?.onlineSourceCount ?? 0} / {detail.sourceStatus.length}在线来源 / 全部
diff --git a/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx b/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx index 5372f326..11cb18c5 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx @@ -8,6 +8,7 @@ import type { Page, VehicleCoverageRow } from '../../api/types'; import { usePlatformSession } from '../auth/AuthGate'; import { canAdminister } from '../auth/session'; import { formatZhNumber } from '../domain/formatters'; +import { protocolDisplayLabel } from '../domain/protocols'; import { useMobileLayout } from '../hooks/useMobileLayout'; import { QUERY_MEMORY, queryScopeKey, retainPreviousPageWithinScope } from '../queryPolicy'; import { TablePagination } from '../shared/TablePagination'; @@ -177,26 +178,26 @@ export default function VehicleSearchWorkspace() { ?
{candidates.error instanceof Error ? candidates.error.message : '授权车辆加载失败'}
: pageVehicles.length ? mobileLayout ?
- {pageVehicles.map((vehicle) => )} + {pageVehicles.map((vehicle) =>
+ +
)}
:
{protocols.length ? protocols.slice(0, 3).map((protocol) => {protocol}) : 暂无来源} + render: (protocols: string[]) => {protocols.length ? protocols.slice(0, 3).map((protocol) => {protocolDisplayLabel(protocol)}) : 暂无来源} }, { title: '', diff --git a/vehicle-data-platform/apps/web/src/v2/shared/VehicleCandidateList.test.tsx b/vehicle-data-platform/apps/web/src/v2/shared/VehicleCandidateList.test.tsx index 8f28a468..4b5c4f4b 100644 --- a/vehicle-data-platform/apps/web/src/v2/shared/VehicleCandidateList.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/shared/VehicleCandidateList.test.tsx @@ -24,10 +24,10 @@ test('renders consistent Semi vehicle options and keeps plate first', () => { expect(screen.getByText('车辆候选')).toBeInTheDocument(); expect(screen.getByText('1/20 已选')).toBeInTheDocument(); - const option = screen.getByRole('option', { name: '粤A00001 VIN001 GB32960 JT808 选择' }); + const option = screen.getByRole('option', { name: '粤A00001 VIN001 GB/T 32960 JT/T 808 选择' }); expect(option).toHaveClass('semi-button', 'v2-vehicle-option'); - expect(option).toHaveTextContent('粤A00001VIN001GB32960JT808选择'); - expect(screen.getByRole('option', { name: '粤A00002 VIN002 JT808 已分配' })).toHaveAttribute('aria-selected', 'true'); + expect(option).toHaveTextContent('粤A00001VIN001GB/T 32960JT/T 808选择'); + expect(screen.getByRole('option', { name: '粤A00002 VIN002 JT/T 808 已分配' })).toHaveAttribute('aria-selected', 'true'); fireEvent.click(option); expect(onSelect).toHaveBeenCalledWith(vehicles[0]); diff --git a/vehicle-data-platform/apps/web/src/v2/shared/VehicleCandidateList.tsx b/vehicle-data-platform/apps/web/src/v2/shared/VehicleCandidateList.tsx index eaed9b04..73ea5d21 100644 --- a/vehicle-data-platform/apps/web/src/v2/shared/VehicleCandidateList.tsx +++ b/vehicle-data-platform/apps/web/src/v2/shared/VehicleCandidateList.tsx @@ -1,5 +1,6 @@ import { Button, Spin, Tag } from '@douyinfe/semi-ui'; import type { ReactNode } from 'react'; +import { protocolDisplayLabel } from '../domain/protocols'; import { VehicleOptionError } from './VehicleOptionError'; export interface VehicleCandidateItem { @@ -57,6 +58,7 @@ export function VehicleCandidateList({ const selected = selectedVins?.has(vehicle.vin) ?? false; const label = selected ? selectedLabel : actionLabel; const protocols = showProtocols ? (vehicle.protocols ?? []).filter(Boolean) : []; + const protocolLabels = protocols.map(protocolDisplayLabel); return ; }) : null} diff --git a/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx b/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx index 4dea4ae0..79511ec9 100644 --- a/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx +++ b/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx @@ -3,6 +3,7 @@ import { Button, Card, Empty, Input, Spin, Tag } from '@douyinfe/semi-ui'; import { useMemo, useState } from 'react'; import { api } from '../../api/client'; import type { VehicleLocationSourceEvidence, VehicleMileageSourceEvidence } from '../../api/types'; +import { protocolDisplayLabel, protocolSourceLabel } from '../domain/protocols'; import { QUERY_MEMORY } from '../queryPolicy'; function today() { @@ -37,9 +38,15 @@ function sourceBadges(source: Pick; } +function evidenceSourceLabel(sourceLabel: string | undefined, protocol: string) { + const normalized = sourceLabel?.trim(); + if (!normalized || normalized === protocol) return protocolDisplayLabel(protocol); + return protocolSourceLabel(normalized); +} + function LocationSourceCard({ source }: { source: VehicleLocationSourceEvidence }) { return -
{source.sourceLabel || source.protocol}{source.protocol}{source.terminalLabel ? ` · ${source.terminalLabel}` : ''}
+
{evidenceSourceLabel(source.sourceLabel, source.protocol)}{protocolDisplayLabel(source.protocol)}{source.terminalLabel ? ` · ${source.terminalLabel}` : ''}
坐标
{coordinate(source)}
速度
{source.speedKmh == null ? '—' : `${number(source.speedKmh)} km/h`}
@@ -55,7 +62,7 @@ function LocationSourceCard({ source }: { source: VehicleLocationSourceEvidence function MileageSourceCard({ source }: { source: VehicleMileageSourceEvidence }) { const comparable = { ...source, online: true }; return -
{source.sourceLabel || source.protocol}{source.protocol}{source.terminalLabel ? ` · ${source.terminalLabel}` : ''}
+
{evidenceSourceLabel(source.sourceLabel, source.protocol)}{protocolDisplayLabel(source.protocol)}{source.terminalLabel ? ` · ${source.terminalLabel}` : ''}
当日里程
{source.dailyMileageKm == null ? '—' : `${number(source.dailyMileageKm)} km`}
最新总里程
{source.latestTotalMileageKm == null ? '—' : `${number(source.latestTotalMileageKm)} km`}
@@ -96,7 +103,7 @@ export function VehicleSourceEvidencePanel({ }); const sourceCount = (query.data?.locationSources.length ?? 0) + (query.data?.mileageSources.length ?? 0); const description = useMemo(() => { - if (!query.data) return '按需读取,不影响车辆列表和地图刷新性能'; + if (!query.data) return '按需读取,不影响实时刷新'; if (sourceCount <= 2) return '当前车辆来源较少,仅展示实际存在的证据'; return `已读取 ${query.data.locationSources.length} 个位置来源、${query.data.mileageSources.length} 个里程来源`; }, [query.data, sourceCount]); @@ -109,13 +116,13 @@ export function VehicleSourceEvidencePanel({ {expanded ?
- 终端标识已脱敏;推荐结果来自后台选举,展开不会改变原始证据。 + 终端已脱敏;推荐结果来自后台选举,不改动原始证据。
{query.isPending ?
正在读取全部来源证据…
: null} {query.isError ?
{query.error instanceof Error ? query.error.message : '来源证据读取失败'}
: null} {query.data ? <>
-
推荐位置来源{query.data.recommendedLocationLabel || query.data.recommendedLocationProtocol || '—'}
+
推荐位置来源{evidenceSourceLabel(query.data.recommendedLocationLabel, query.data.recommendedLocationProtocol)}
最大位置差{number(query.data.comparison.locationMaxDistanceM)}m
总里程差{number(query.data.comparison.totalMileageDeltaKm)}km
上报时间差{number(query.data.comparison.reportTimeDeltaSeconds, 0)}s
diff --git a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css index 67ad51b0..75abd0dc 100644 --- a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css +++ b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css @@ -2472,6 +2472,14 @@ grid-template-columns: repeat(4, minmax(0, 1fr)); } +.v2-vehicle-recent-item-shell { + min-width: 0; +} + +.v2-vehicle-recent-item-shell > .v2-vehicle-recent-item.semi-button { + height: 100%; +} + .v2-vehicle-recent-item.semi-button { min-height: 78px; } @@ -2771,6 +2779,10 @@ grid-template-columns: 1fr; } + .v2-vehicle-recent-item-shell:last-child > .v2-vehicle-recent-item.semi-button { + border-bottom: 0; + } + .v2-vehicle-recent-card > .semi-card-body > .v2-vehicle-directory-pagination { min-height: 52px; padding-inline: 10px;