From e02d8dba541960abc4d43bf9fb01da9bdb0eb320 Mon Sep 17 00:00:00 2001 From: lingniu Date: Sun, 19 Jul 2026 10:48:08 +0800 Subject: [PATCH] feat: simplify login and unify monitor summary --- .../apps/web/src/v2/auth/AuthGate.test.tsx | 33 +- .../apps/web/src/v2/auth/AuthGate.tsx | 63 +--- .../web/src/v2/pages/MonitorPage.test.tsx | 20 +- .../apps/web/src/v2/pages/MonitorPage.tsx | 73 +++- .../apps/web/src/v2/productionEntry.test.ts | 9 +- .../apps/web/src/v2/styles/workspace.css | 312 +++++++++++++----- 6 files changed, 329 insertions(+), 181 deletions(-) diff --git a/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.test.tsx b/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.test.tsx index 63f4b912..c0eb64da 100644 --- a/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.test.tsx @@ -88,35 +88,20 @@ test('treats login and logout as complete query and mutation cache boundaries', expect(window.sessionStorage.length).toBe(0); }); -test('makes account and operations-token entry explicit while preserving the account draft', async () => { +test('exposes only account and password login on the public sign-in screen', async () => { const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); - mocks.session.mockImplementation(async () => { - if (getAccessToken() !== 'ops-session-token') throw new Error('未登录'); - return { name: 'platform-operator', role: 'admin', authMode: 'enforce' }; - }); + mocks.session.mockRejectedValue(new Error('未登录')); render( undefined} />); expect(await screen.findByRole('form', { name: '平台账号登录' })).toBeInTheDocument(); - expect(screen.getByRole('tab', { name: '账号登录' })).toHaveAttribute('aria-selected', 'true'); - expect(screen.getByRole('tab', { name: '运维令牌' })).toHaveAttribute('aria-selected', 'false'); - fireEvent.change(screen.getByPlaceholderText('请输入用户名'), { target: { value: 'remember-me' } }); - - fireEvent.click(screen.getByRole('tab', { name: '运维令牌' })); - expect(screen.getByRole('form', { name: '运维令牌登录' })).toBeInTheDocument(); - expect(screen.getByText('仅限平台运维')).toBeInTheDocument(); - expect(screen.getByText('令牌只保存在当前浏览器会话,关闭或退出后失效。')).toBeInTheDocument(); - expect(screen.queryByRole('button', { name: 'Close' })).not.toBeInTheDocument(); - fireEvent.change(screen.getByPlaceholderText('请输入服务器访问令牌'), { target: { value: 'ops-session-token' } }); - - fireEvent.click(screen.getByRole('tab', { name: '账号登录' })); - expect(screen.getByPlaceholderText('请输入用户名')).toHaveValue('remember-me'); - fireEvent.click(screen.getByRole('tab', { name: '运维令牌' })); - fireEvent.click(screen.getByRole('button', { name: '验证令牌并进入' })); - - expect(await screen.findByText('platform-operator')).toBeInTheDocument(); - expect(mocks.login).not.toHaveBeenCalled(); - expect(getAccessToken()).toBe('ops-session-token'); + expect(screen.getByPlaceholderText('请输入用户名')).toHaveAttribute('autocomplete', 'username'); + expect(screen.getByPlaceholderText('请输入密码')).toHaveAttribute('autocomplete', 'current-password'); + expect(screen.queryByRole('tab')).not.toBeInTheDocument(); + expect(screen.queryByText('运维令牌')).not.toBeInTheDocument(); + expect(screen.queryByPlaceholderText('请输入服务器访问令牌')).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: '验证令牌并进入' })).not.toBeInTheDocument(); + expect(screen.getByRole('button', { name: '登录工作台' })).toBeDisabled(); }); test('an expired protected request returns to login and removes the active user cache', async () => { diff --git a/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.tsx b/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.tsx index d9459503..168f6bca 100644 --- a/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.tsx +++ b/vehicle-data-platform/apps/web/src/v2/auth/AuthGate.tsx @@ -1,6 +1,6 @@ -import { IconAlertTriangle, IconKey, IconLock, IconSafe, IconShield, IconUser } from '@douyinfe/semi-icons'; +import { IconAlertTriangle, IconLock, IconSafe, IconShield, IconUser } from '@douyinfe/semi-icons'; import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { Banner, Button, Card, Input, Spin, Tabs, Tag, Typography } from '@douyinfe/semi-ui'; +import { Banner, Button, Card, Input, Spin, Tag, Typography } from '@douyinfe/semi-ui'; import { FormEvent, ReactNode, useCallback, useContext, useEffect, useState, createContext } from 'react'; import { api } from '../../api/client'; import { PasswordInput } from '../shared/PasswordInput'; @@ -79,8 +79,6 @@ export function AuthGate({ children }: { children: ReactNode }) { const [tokenVersion, setTokenVersion] = useState(0); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); - const [draftToken, setDraftToken] = useState(''); - const [legacyMode, setLegacyMode] = useState(false); const [attempted, setAttempted] = useState(() => Boolean(getAccessToken())); const [loginPending, setLoginPending] = useState(false); const [loginError, setLoginError] = useState(''); @@ -98,7 +96,6 @@ export function AuthGate({ children }: { children: ReactNode }) { clearAccessToken(); clearClientSession(); setPassword(''); - setDraftToken(''); setAttempted(false); setLoginError(''); setTokenVersion((value) => value + 1); @@ -117,12 +114,8 @@ export function AuthGate({ children }: { children: ReactNode }) { setLoginError(''); setLoginPending(true); try { - if (legacyMode) { - setAccessToken(draftToken); - } else { - const result = await api.login({ username: username.trim(), password }); - setAccessToken(result.accessToken); - } + const result = await api.login({ username: username.trim(), password }); + setAccessToken(result.accessToken); clearClientSession(); setTokenVersion((value) => value + 1); } catch (error) { @@ -132,11 +125,6 @@ export function AuthGate({ children }: { children: ReactNode }) { setLoginPending(false); } }; - const switchLoginMode = (mode: string) => { - setLegacyMode(mode === 'token'); - setLoginError(''); - }; - if (session.isPending) { return ; } @@ -159,45 +147,20 @@ export function AuthGate({ children }: { children: ReactNode }) {
账号、车辆与菜单权限全程隔离
-
+
羚牛智能 - : }> - {legacyMode ? '受控运维入口' : '账号权限登录'} - + }>账号权限登录 登录车辆数据中台 - {legacyMode ? '仅供平台运维使用,输入服务器访问令牌。' : '使用管理员为你开通的账号登录。'} + 使用管理员为你开通的账号登录。
- - - - +
+ + +
{error ? : null} -
登录后按账号隔离菜单、车辆和本地缓存
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 cc002826..c7f47883 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 @@ -118,15 +118,19 @@ test('starts without a selection and supports expand, collapse, reselection, and expect(firstVehicle).toHaveClass('semi-button', 'v2-vehicle-row'); expect(view.container.querySelector('.v2-filterbar')).toHaveClass('semi-card'); - const kpis = view.container.querySelector('.v2-kpis'); - expect(kpis).toHaveClass('semi-card'); - expect(Array.from(kpis?.querySelectorAll('.v2-kpi small') ?? []).map((item) => item.textContent)).toEqual([ - '车辆总数', '当前在线', '当前离线', '行驶车辆', '静止车辆', '告警车辆', '今日上报', '无实时位置' + const kpis = screen.getByRole('list', { name: '车辆整体统计' }); + expect(kpis.closest('.v2-monitor-summary-rail')).toHaveClass('semi-card', 'v2-workspace-metric-rail', 'is-queue'); + expect(Array.from(kpis.querySelectorAll(':scope > [role="listitem"] > small')).map((item) => item.textContent)).toEqual([ + '车辆总数', '当前在线', '行驶车辆', '当前离线', '静止车辆', '告警车辆' ]); - expect(kpis?.querySelector('.v2-kpi.is-fleet')).toHaveClass('is-primary'); - expect(kpis?.querySelector('.v2-kpi.is-online')).toHaveClass('is-primary'); - expect(kpis?.querySelector('.v2-kpi.is-today')).toHaveClass('is-support'); - expect(kpis?.querySelector('.v2-kpi:last-child')).toHaveClass('is-missing', 'is-support'); + expect(kpis.querySelectorAll(':scope > [role="listitem"]')).toHaveLength(6); + expect(kpis.querySelector(':scope > [role="listitem"]:nth-child(1)')).toHaveClass('is-primary'); + expect(kpis.querySelector(':scope > [role="listitem"]:nth-child(2)')).toHaveClass('is-primary', 'is-success'); + expect(kpis.querySelector(':scope > [role="listitem"]:nth-child(4)')).toHaveClass('is-secondary'); + const summarySupport = view.container.querySelector('.v2-monitor-summary-support'); + expect(summarySupport).toHaveTextContent('今日上报10条数据活跃度'); + expect(summarySupport).toHaveTextContent('无实时位置0辆辅助排查'); + expect(view.container.querySelector('.v2-kpis')).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-event-strip')).toHaveClass('semi-card'); expect(view.container.querySelector('.v2-monitor-live-tag')).toHaveClass('semi-tag'); const liveStatus = screen.getByLabelText('实时数据状态'); 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 9151bf8f..dc05c5d5 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/MonitorPage.tsx @@ -13,6 +13,7 @@ import { EmptyState, InlineError } from '../shared/AsyncState'; import { SegmentedTabs } from '../shared/SegmentedTabs'; import { TablePagination } from '../shared/TablePagination'; import { ProtocolTag } from '../shared/ProtocolTag'; +import { WorkspaceMetricRail, type WorkspaceQueueMetricRailItem } from '../shared/WorkspaceMetricRail'; import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader'; import { WorkspaceSideSheet } from '../shared/WorkspaceSideSheet'; import { formatNumber, statusLabel, vehicleStatus } from '../domain/monitor'; @@ -340,6 +341,56 @@ export default function MonitorPage() { const driving = rows.filter((vehicle) => vehicleStatus(vehicle) === 'driving').length; const idle = rows.filter((vehicle) => vehicleStatus(vehicle) === 'idle').length; const offline = rows.filter((vehicle) => vehicleStatus(vehicle) === 'offline').length; + const totalVehicleCount = summary.data?.totalVehicles ?? vehicles.data?.total ?? rows.length; + const onlineVehicleCount = summary.data?.onlineVehicles ?? rows.length - offline; + const offlineVehicleCount = summary.data?.offlineVehicles ?? offline; + const drivingVehicleCount = summary.data?.drivingVehicles ?? driving; + const idleVehicleCount = summary.data?.idleVehicles ?? idle; + const alertVehicleCount = summary.data?.alertDataAvailable ? summary.data.alertVehicles : undefined; + const monitorMetrics: WorkspaceQueueMetricRailItem[] = [ + { + label: '车辆总数', + value: <>{formatNumber(totalVehicleCount)}, + note: '授权车辆', + tone: 'primary', + emphasis: 'primary' + }, + { + label: '当前在线', + value: <>{formatNumber(onlineVehicleCount)}, + note: '当前可用', + tone: 'success', + emphasis: 'primary' + }, + { + label: '行驶车辆', + value: <>{formatNumber(drivingVehicleCount)}, + note: '实时行驶', + tone: 'primary', + emphasis: 'primary' + }, + { + label: '当前离线', + value: <>{formatNumber(offlineVehicleCount)}, + note: '无在线来源', + tone: 'neutral', + emphasis: 'secondary' + }, + { + label: '静止车辆', + value: <>{formatNumber(idleVehicleCount)}, + note: '在线静止', + tone: 'success', + emphasis: 'secondary' + }, + { + label: '告警车辆', + value: <>{alertVehicleCount == null ? '—' : formatNumber(alertVehicleCount)}, + note: alertVehicleCount == null ? '数据未开放' : '需要关注', + tone: alertVehicleCount ? 'danger' : 'neutral', + emphasis: 'primary' + } + ]; const viewportLoad = mode === 'map' ? (map.data?.clusters.length ? `${map.data.clusters.length} 个聚合 · ${map.data.points.length} 个车辆点` @@ -409,18 +460,16 @@ export default function MonitorPage() {
{batchSearchOpen ? setBatchSearchOpen(false)} onApply={(value) => { setKeyword(value); setListOffset(0); setBatchSearchOpen(false); }} /> : null} - - {[ - { label: '车辆总数', value: formatNumber(summary.data?.totalVehicles ?? vehicles.data?.total ?? rows.length), tone: 'fleet', priority: 'primary', unit: '辆' }, - { label: '当前在线', value: formatNumber(summary.data?.onlineVehicles ?? rows.length - offline), tone: 'online', priority: 'primary', unit: '辆' }, - { label: '当前离线', value: formatNumber(summary.data?.offlineVehicles ?? offline), tone: 'offline', priority: 'standard', unit: '辆' }, - { label: '行驶车辆', value: formatNumber(summary.data?.drivingVehicles ?? driving), tone: 'driving', priority: 'standard', unit: '辆' }, - { label: '静止车辆', value: formatNumber(summary.data?.idleVehicles ?? idle), tone: 'idle', priority: 'standard', unit: '辆' }, - { label: '告警车辆', value: summary.data?.alertDataAvailable ? formatNumber(summary.data.alertVehicles) : '—', tone: 'alert', priority: 'standard', unit: '辆' }, - { label: '今日上报', value: formatNumber(summary.data?.frameToday ?? 0), tone: 'today', priority: 'support', unit: '条' }, - { label: '无实时位置', value: formatNumber(summary.data?.noLocationVehicles ?? 0), tone: 'missing', priority: 'support', unit: '辆' } - ].map(({ label, value, tone, priority, unit }) =>
{label}{value}{unit}
)} -
+ + 今日上报{formatNumber(summary.data?.frameToday ?? 0)}数据活跃度 + 无实时位置{formatNumber(summary.data?.noLocationVehicles ?? 0)}辅助排查 + } + /> {vehicles.isError ? vehicles.refetch()} /> : null} {mode === 'list' && realtimeListQuery.isError ? realtimeListQuery.refetch()} /> : null} diff --git a/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts b/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts index 47efe9cd..2f5cc343 100644 --- a/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts +++ b/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts @@ -513,7 +513,10 @@ describe('V2 production entry', () => { expect(corePageSources.MonitorPage).not.toContain(' { expect(vehicleActionsSource).not.toContain('useSideSheetA11y'); expect(appShellSource).toContain('className="v2-password-modal"'); expect(appShellSource.match(/ .v2-auth-fields { min-width: 0; grid-column: 2; grid-row: 1; @@ -462,15 +462,6 @@ margin-top: 0; } - :root .v2-auth-mode-tabs > .semi-tabs-bar { - padding: 3px; - } - - :root .v2-auth-mode-tabs > .semi-tabs-bar .semi-tabs-tab { - height: 32px; - font-size: 10px; - } - :root .v2-auth-fields { min-height: 0; grid-template-columns: repeat(2, minmax(0, 1fr)); @@ -489,19 +480,6 @@ border-radius: 9px; } - :root .v2-auth-token-note.semi-banner { - min-width: 0; - margin-top: 9px; - padding: 6px 7px; - } - - :root .v2-auth-token-note .semi-banner-description { - display: -webkit-box; - overflow: hidden; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - } - :root .v2-auth-error { min-width: 0; grid-column: 2; @@ -5998,39 +5976,10 @@ line-height: 1.65; } -.v2-auth-mode-tabs { +.v2-auth-form > .v2-auth-fields { margin-top: 20px; } -.v2-auth-mode-tabs > .semi-tabs-bar { - width: 100%; - border: 1px solid #e5ebf3; - border-radius: 12px; - background: #f4f7fb; - padding: 4px; -} - -.v2-auth-mode-tabs > .semi-tabs-bar .semi-tabs-tab { - width: 50%; - min-width: 0; - height: 38px; - justify-content: center; - border-radius: 9px; - color: #718096; - font-size: 11px; - font-weight: 650; -} - -.v2-auth-mode-tabs > .semi-tabs-bar .semi-tabs-tab-active { - background: #fff; - color: #1268f3; - box-shadow: 0 2px 8px rgba(30, 58, 92, .1); -} - -.v2-auth-mode-tabs > .semi-tabs-content { - padding: 0; -} - .v2-auth-fields { display: grid; gap: 0; @@ -6066,28 +6015,6 @@ box-shadow: 0 0 0 3px rgba(18, 104, 243, .1); } -.v2-auth-token-note.semi-banner { - align-items: flex-start; - margin-top: 14px; - border: 1px solid #f4d9a7; - border-radius: 10px; - background: #fffbf2; - padding: 9px 10px; -} - -.v2-auth-token-note .semi-banner-title { - color: #815d16; - font-size: 10px; - font-weight: 750; -} - -.v2-auth-token-note .semi-banner-description { - margin-top: 2px; - color: #9b7a37; - font-size: 9px; - line-height: 1.5; -} - .v2-auth-form > .semi-button-primary { height: 46px; margin-top: 18px; @@ -6314,15 +6241,10 @@ font-size: 11px; } - .v2-auth-mode-tabs { + .v2-auth-form > .v2-auth-fields { margin-top: 17px; } - .v2-auth-mode-tabs > .semi-tabs-bar .semi-tabs-tab { - height: 40px; - font-size: 12px; - } - .v2-auth-fields { min-height: 143px; } @@ -6340,10 +6262,6 @@ font-size: 13px; } - .v2-auth-token-note.semi-banner { - margin-top: 12px; - } - .v2-route-error > .v2-route-error-card.semi-card { border-radius: 15px; } @@ -23090,3 +23008,227 @@ display: flex; } } + +/* + * Monitor fleet summary. + * Operational state remains prominent; high-volume ingest evidence is kept + * in a quieter support lane so the map stays the page's visual focus. + */ +.v2-monitor-summary-rail.is-queue.semi-card { + border: 1px solid #dce5ef; + border-radius: 12px; + box-shadow: 0 7px 24px rgba(31, 53, 80, .05); +} + +.v2-monitor-summary-rail.is-queue > .semi-card-body { + min-height: 74px; + grid-template-columns: minmax(0, 1fr) minmax(206px, .8fr); +} + +.v2-monitor-summary-rail .v2-workspace-metric-list { + grid-template-columns: 1.13fr 1.13fr 1.03fr .9fr .9fr 1fr; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span { + min-height: 74px; + column-gap: 8px; + padding: 10px 14px; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span.is-primary { + background: linear-gradient(145deg, #f6faff 0%, #fff 78%); + box-shadow: inset 0 2px #5b96ee; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span.is-primary.is-success { + background: linear-gradient(145deg, #f4fbf7 0%, #fff 78%); + box-shadow: inset 0 2px #4fbd8d; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span.is-primary.is-danger { + background: linear-gradient(145deg, #fff8f7 0%, #fff 78%); + box-shadow: inset 0 2px #e36a64; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span > small { + font-size: 10px; + line-height: 15px; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span > strong { + overflow: hidden; + font-size: clamp(22px, 1.75vw, 29px); + font-weight: 750; + letter-spacing: -.025em; + line-height: 29px; + text-overflow: ellipsis; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span.is-secondary > strong { + color: #5f6f82; + font-size: clamp(18px, 1.35vw, 22px); + font-weight: 680; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span > em { + max-width: 72px; + color: #8794a5; + font-size: 8px; +} + +.v2-monitor-summary-unit { + margin-left: 4px; + color: #8b98a9; + font-size: 8px; + font-style: normal; + font-weight: 600; + letter-spacing: 0; +} + +.v2-monitor-summary-rail .v2-workspace-metric-list > span.is-primary .v2-monitor-summary-unit { + color: #7392ba; +} + +.v2-monitor-summary-rail .v2-workspace-metric-context { + min-height: 74px; + padding: 0; +} + +.v2-monitor-summary-support { + display: grid; + width: 100%; + min-width: 0; + grid-template-columns: 1.15fr 1fr; +} + +.v2-monitor-summary-support > span { + display: grid; + min-width: 0; + min-height: 74px; + align-content: center; + padding: 9px 13px; +} + +.v2-monitor-summary-support > span + span { + border-left: 1px solid #e5ebf2; +} + +.v2-monitor-summary-support small { + color: #8b97a6; + font-size: 8px; + font-weight: 600; + line-height: 13px; +} + +.v2-monitor-summary-support strong { + overflow: hidden; + color: #69798e; + font-size: clamp(15px, 1.18vw, 19px); + font-variant-numeric: tabular-nums; + font-weight: 650; + line-height: 22px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.v2-monitor-summary-support strong > i { + margin-left: 3px; + color: #99a4b2; + font-size: 7px; + font-style: normal; + font-weight: 550; +} + +.v2-monitor-summary-support em { + overflow: hidden; + color: #a0a9b5; + font-size: 7px; + font-style: normal; + line-height: 11px; + text-overflow: ellipsis; + white-space: nowrap; +} + +@media (max-width: 1120px) { + .v2-monitor-summary-rail.is-queue > .semi-card-body { + grid-template-columns: minmax(0, 1fr) 188px; + } + + .v2-monitor-summary-rail .v2-workspace-metric-list > span { + padding-inline: 10px; + } + + .v2-monitor-summary-rail .v2-workspace-metric-list > span > em { + display: none; + } +} + +@media (max-width: 680px) { + .v2-monitor-summary-rail.is-queue > .semi-card-body { + min-height: 132px; + grid-template-columns: minmax(0, 1fr); + } + + .v2-monitor-summary-rail .v2-workspace-metric-list { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .v2-monitor-summary-rail .v2-workspace-metric-list > span { + min-height: 48px; + padding: 5px 11px; + } + + .v2-monitor-summary-rail .v2-workspace-metric-list > span.is-secondary { + display: none; + } + + .v2-monitor-summary-rail .v2-workspace-metric-list > span:nth-child(3), + .v2-monitor-summary-rail .v2-workspace-metric-list > span:nth-child(6) { + border-top: 1px solid #e5ebf2; + } + + .v2-monitor-summary-rail .v2-workspace-metric-list > span:nth-child(3) { + border-left: 0; + } + + .v2-monitor-summary-rail .v2-workspace-metric-list > span > strong, + .v2-monitor-summary-rail .v2-workspace-metric-list > span.is-secondary > strong { + font-size: 19px; + line-height: 21px; + } + + .v2-monitor-summary-rail .v2-workspace-metric-list > span > em { + display: block; + max-width: none; + font-size: 7px; + } + + .v2-monitor-summary-rail .v2-workspace-metric-context { + display: flex; + min-height: 36px; + border-top: 1px solid #e5ebf2; + border-left: 0; + } + + .v2-monitor-summary-support > span { + min-height: 36px; + grid-template-columns: auto minmax(0, 1fr); + align-items: baseline; + align-content: center; + gap: 0 5px; + padding: 4px 11px; + } + + .v2-monitor-summary-support small { + font-size: 8px; + } + + .v2-monitor-summary-support strong { + font-size: 14px; + line-height: 17px; + } + + .v2-monitor-summary-support em { + display: none; + } +}