diff --git a/src/pages/UsageRecordsPage.tsx b/src/pages/UsageRecordsPage.tsx
index 3a58062..6a70739 100644
--- a/src/pages/UsageRecordsPage.tsx
+++ b/src/pages/UsageRecordsPage.tsx
@@ -1028,7 +1028,7 @@ function OverviewView({ overview, range }: { overview: UsageOverview; range?: Pi
},
{
label: t('usage.stat.tps'),
- value: overview.tpsSampleCount > 0 ? `${overview.tps.toFixed(1)} TPS` : '—',
+ value: overview.tpsSampleCount > 0 ? overview.tps.toFixed(1) : '—',
meta: t('usage.stat.performanceMeta', {
samples: compactNumber(overview.tpsSampleCount),
rpm: overview.rpm.toFixed(2),
@@ -1073,12 +1073,9 @@ function OverviewView({ overview, range }: { overview: UsageOverview; range?: Pi
{cards.map(({ label, value, meta, metaTitle }) => (
-
+
{label}
{value}
-
- {meta}
-
))}
diff --git a/src/styles.css b/src/styles.css
index db8241c..a70999b 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -8439,47 +8439,53 @@ textarea:focus-visible {
.usage-stat-grid {
grid-column: 1 / -1;
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
- gap: 12px;
+ grid-template-columns: repeat(6, minmax(0, 1fr));
+ gap: 10px;
}
.usage-stat-card {
- display: grid;
- gap: 8px;
- padding: 14px 16px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 5px;
+ padding: 10px 12px;
border: 1px solid var(--theme-e3e1db);
- border-radius: 9px;
+ border-radius: 8px;
background: var(--theme-fffdf8);
+ min-width: 0;
transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.usage-stat-card:hover {
border-color: var(--theme-d5d2cb);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+ transform: translateY(-1px);
}
.usage-stat-card-label {
color: var(--theme-7a746c);
- font-size: var(--font-size-meta);
- font-weight: var(--font-weight-semibold);
+ font-size: var(--font-size-caption);
+ font-weight: var(--font-weight-medium);
+ line-height: 1.25;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.usage-stat-card-value {
color: var(--theme-2d2a26);
- font-size: var(--font-size-metric-compact);
+ font-size: 20px;
font-weight: var(--font-weight-semibold);
font-variant-numeric: tabular-nums;
- line-height: 1.15;
+ line-height: 1.2;
letter-spacing: -0.01em;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.usage-stat-card-meta {
- color: var(--theme-8a847c);
- font-size: var(--font-size-caption);
- line-height: 1.3;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
+ display: none;
}
/* Trend Panel */
@@ -10851,10 +10857,6 @@ body.table-col-resizing * {
grid-template-columns: 200px minmax(0, 1fr);
}
- .usage-stat-grid {
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
- }
-
.control-panel,
.version-panel {
grid-column: auto;
@@ -11321,7 +11323,7 @@ body.table-col-resizing * {
}
.usage-stat-grid {
- grid-template-columns: 1fr;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
}
.usage-custom-range {
@@ -14554,13 +14556,13 @@ body.table-col-resizing * {
.agent-workbench {
grid-template-columns: 200px minmax(0, 1fr);
}
-
- .usage-stat-grid {
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
- }
}
@container workspace (max-width: 760px) {
+ .usage-stat-grid {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
.config-network-grid,
.config-tls-fields,
.config-management-form,
@@ -14725,6 +14727,12 @@ body.table-col-resizing * {
}
}
+@container workspace (max-width: 480px) {
+ .usage-stat-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+}
+
@container workspace (max-width: 540px) {
.usage-data-management-heading,
.usage-data-management-action,
diff --git a/tests/usage-layout-ui.cjs b/tests/usage-layout-ui.cjs
index 880504c..b507077 100644
--- a/tests/usage-layout-ui.cjs
+++ b/tests/usage-layout-ui.cjs
@@ -6,11 +6,34 @@ const base = 'http://127.0.0.1:1421';
(async () => {
const browser = await chromium.launch({ channel: 'msedge', headless: true, args: ['--no-proxy-server'] });
try {
- const page = await browser.newPage({ viewport: { width: 1100, height: 600 } });
+ const page = await browser.newPage({ viewport: { width: 1213, height: 600 } });
await page.route('**/*', (route) => route.request().url().startsWith(`${base}/`) ? route.continue() : route.abort());
await page.goto(`${base}/tests/fixtures/usage-layout.html`, { waitUntil: 'domcontentloaded' });
await page.locator('.usage-trend-x-axis').waitFor();
+ const statInfo1213 = await page.evaluate(() => {
+ const cards = Array.from(document.querySelectorAll('.usage-stat-card'));
+ const metas = Array.from(document.querySelectorAll('.usage-stat-card-meta'));
+ const tpsCard = cards.find((card) => card.querySelector('.usage-stat-card-label')?.textContent?.trim() === 'TPS');
+ const tpsValue = tpsCard?.querySelector('.usage-stat-card-value')?.textContent?.trim() ?? '';
+ return {
+ cardCount: cards.length,
+ metaCount: metas.length,
+ cardRows: new Set(cards.map((card) => Math.round(card.getBoundingClientRect().top))).size,
+ tpsValue,
+ };
+ });
+
+ assert.equal(statInfo1213.cardCount, 6, 'There are 6 stat cards');
+ assert.equal(statInfo1213.cardRows, 1, 'At 1213px width, all 6 cards fit into a single row');
+ assert.equal(statInfo1213.metaCount, 0, 'Stat cards have no meta subtext displayed');
+ assert.ok(!statInfo1213.tpsValue.includes('TPS'), `TPS value should not contain TPS unit: ${statInfo1213.tpsValue}`);
+ assert.ok(/^\d+(\.\d+)?$/.test(statInfo1213.tpsValue), `TPS value should be numeric: ${statInfo1213.tpsValue}`);
+
+ // Now test constrained width where cards wrap and ensure vertical scrolling is preserved
+ await page.setViewportSize({ width: 750, height: 600 });
+ await page.waitForTimeout(100);
+
const geometry = await page.evaluate(() => {
const layout = document.querySelector('.usage-overview-layout');
const panel = document.querySelector('.usage-trend-panel');
@@ -45,7 +68,7 @@ const base = 'http://127.0.0.1:1421';
return axis.getBoundingClientRect().bottom <= layout.getBoundingClientRect().bottom + 1;
}), 'The complete X axis is reachable by scrolling the overview');
- console.log('PASS: wrapped usage cards preserve the full trend chart and use vertical overview scrolling.');
+ console.log('PASS: 1213px single row stat cards and constrained wrapped overview scrolling passed.');
} finally {
await browser.close();
}