fix(ui): group mobile system metrics (#3880)
Co-authored-by: Kandev Agent <agent@kandev.dev>
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
import { expect, test } from "../../fixtures/test-base";
|
||||
import { waitForFiniteAnimations } from "../../helpers/animations";
|
||||
import {
|
||||
assertNoDocumentHorizontalOverflow,
|
||||
assertNoElementHorizontalOverflow,
|
||||
requireBox,
|
||||
} from "../../helpers/layout-assertions";
|
||||
import {
|
||||
captureAppStatusBarSettings,
|
||||
restoreAppStatusBarSettings,
|
||||
@@ -29,7 +35,8 @@ test.describe("Mobile resource metrics display", () => {
|
||||
let statusBarBaseline: AppStatusBarSettingsBaseline;
|
||||
let globalMetricsBaseline: SystemMetricsGlobalSettings;
|
||||
|
||||
test.beforeEach(async ({ apiClient }) => {
|
||||
test.beforeEach(async ({ apiClient, testPage }) => {
|
||||
void testPage;
|
||||
const settings = await apiClient.getUserSettings();
|
||||
baseline = settings.settings.system_metrics_display as SystemMetricsDisplay;
|
||||
statusBarBaseline = await captureAppStatusBarSettings(apiClient);
|
||||
@@ -58,7 +65,7 @@ test.describe("Mobile resource metrics display", () => {
|
||||
await restoreAppStatusBarSettings(apiClient, statusBarBaseline);
|
||||
});
|
||||
|
||||
test("stacks all enabled metrics inside the Status drawer", async ({ testPage, apiClient }) => {
|
||||
test("aligns all enabled metrics inside the Status drawer", async ({ testPage, apiClient }) => {
|
||||
const globalMetricsUpdate = await apiClient.rawRequest(
|
||||
"PATCH",
|
||||
"/api/v1/system/metrics/settings",
|
||||
@@ -71,12 +78,13 @@ test.describe("Mobile resource metrics display", () => {
|
||||
expect(displayUpdate.ok).toBe(true);
|
||||
|
||||
await testPage.goto("/");
|
||||
await testPage.getByTestId("app-nav-trigger").click();
|
||||
await testPage.getByTestId("mobile-home-status-button").click();
|
||||
await testPage.getByTestId("app-nav-trigger").tap();
|
||||
await testPage.getByTestId("mobile-home-status-button").tap();
|
||||
|
||||
const drawer = testPage.getByTestId("app-status-drawer");
|
||||
const metrics = drawer.getByTestId("app-status-metrics");
|
||||
await expect(metrics.getByLabel(/^CPU (?!temperature)/)).toBeVisible();
|
||||
await waitForFiniteAnimations(testPage.getByRole("dialog", { name: "Status", exact: true }));
|
||||
const geometry = await metrics.evaluate((element) => {
|
||||
const indicators = Array.from(
|
||||
element.querySelectorAll<HTMLElement>('span[aria-label]:not([aria-label="Host metrics"])'),
|
||||
@@ -105,17 +113,88 @@ test.describe("Mobile resource metrics display", () => {
|
||||
};
|
||||
});
|
||||
|
||||
expect(geometry.rowCount).toBe(3);
|
||||
expect(geometry.firstRowCount).toBe(2);
|
||||
expect(geometry.rowCount).toBe(2);
|
||||
expect(geometry.firstRowCount).toBe(3);
|
||||
expect(geometry.count).toBe(5);
|
||||
expect(geometry.contained).toBe(true);
|
||||
expect(geometry.valuesScrollWidth).toBeLessThanOrEqual(geometry.valuesClientWidth + 1);
|
||||
for (const label of ["CPU", "Memory", "Disk", "CPU temperature", "System load (1 min)"]) {
|
||||
const reading = metrics.getByText(label, { exact: true });
|
||||
await reading.scrollIntoViewIfNeeded();
|
||||
await expect(reading).toBeInViewport();
|
||||
}
|
||||
expect(await drawer.locator("[class*='overflow-y-auto']").count()).toBe(1);
|
||||
expect(await testPage.evaluate(() => document.documentElement.scrollWidth)).toBe(
|
||||
await testPage.evaluate(() => document.documentElement.clientWidth),
|
||||
);
|
||||
});
|
||||
|
||||
test("groups the default readings in one compact card in the phone menu", async ({
|
||||
testPage,
|
||||
apiClient,
|
||||
prCapture,
|
||||
}) => {
|
||||
await setAppStatusBarEnabled(apiClient, false);
|
||||
const globalUpdate = await apiClient.rawRequest("PATCH", "/api/v1/system/metrics/settings", {
|
||||
...globalMetricsBaseline,
|
||||
metrics: ALL_HOST_METRICS.slice(0, 3),
|
||||
});
|
||||
expect(globalUpdate.ok).toBe(true);
|
||||
const displayUpdate = await apiClient.rawRequest("PATCH", "/api/v1/user/settings", {
|
||||
system_metrics_display: { show_in_topbar: true, simplified: false },
|
||||
});
|
||||
expect(displayUpdate.ok).toBe(true);
|
||||
await testPage.emulateMedia({ colorScheme: "dark" });
|
||||
await testPage.goto("/");
|
||||
|
||||
for (const width of [393, 320, 767]) {
|
||||
await testPage.setViewportSize({ width, height: 851 });
|
||||
const trigger = testPage.getByTestId("app-nav-trigger");
|
||||
await trigger.tap();
|
||||
const menu = testPage.getByTestId("app-nav-sheet");
|
||||
const metrics = menu.getByTestId("app-status-metrics");
|
||||
await expect(metrics.getByLabel(/^CPU /)).toBeVisible();
|
||||
await metrics.scrollIntoViewIfNeeded();
|
||||
await waitForFiniteAnimations(menu);
|
||||
const heading = await requireBox(metrics.getByRole("heading"), "metrics heading");
|
||||
const host = await requireBox(metrics.getByLabel("Host metrics"), "host badge");
|
||||
expect(
|
||||
Math.abs(heading.y + heading.height / 2 - host.y - host.height / 2),
|
||||
).toBeLessThanOrEqual(1);
|
||||
const boxes = [];
|
||||
for (const label of ["CPU", "Memory", "Disk"]) {
|
||||
await expect(metrics.getByText(label, { exact: true })).toBeVisible();
|
||||
const reading = metrics.getByLabel(new RegExp(`^${label} `));
|
||||
boxes.push(await requireBox(reading, label));
|
||||
await assertNoElementHorizontalOverflow(reading, label);
|
||||
}
|
||||
for (const box of boxes) {
|
||||
expect(box.y).toBeCloseTo(boxes[0].y, 0);
|
||||
expect(box.width).toBeCloseTo(boxes[0].width, 0);
|
||||
expect(box.height).toBeGreaterThanOrEqual(44);
|
||||
}
|
||||
await assertNoElementHorizontalOverflow(metrics);
|
||||
await assertNoDocumentHorizontalOverflow(testPage);
|
||||
await expect(menu.locator("nav.overflow-y-auto")).toHaveCount(1);
|
||||
if (width === 393) {
|
||||
if (prCapture.capturing) await expect(testPage.getByTestId("toast-message")).toHaveCount(0);
|
||||
await prCapture.screenshot("system-metrics-menu-mobile", {
|
||||
caption: "CPU, memory, and disk grouped in the phone menu's built-in System metrics card",
|
||||
});
|
||||
}
|
||||
await testPage.keyboard.press("Escape");
|
||||
await expect(menu).toBeHidden();
|
||||
await expect(trigger).toBeFocused();
|
||||
}
|
||||
await testPage.setViewportSize({ width: 768, height: 851 });
|
||||
await expect(testPage.getByTestId("app-nav-trigger")).toBeHidden();
|
||||
const metrics = testPage.getByTestId("app-status-metrics");
|
||||
await expect(metrics.getByLabel(/^CPU /)).toBeVisible();
|
||||
await expect(metrics).toHaveCSS("display", "flex");
|
||||
await expect(metrics.getByRole("heading")).toHaveCount(0);
|
||||
await assertNoDocumentHorizontalOverflow(testPage);
|
||||
});
|
||||
|
||||
test("renders simplified metrics in the Status drawer", async ({ testPage }) => {
|
||||
await testPage.goto("/settings");
|
||||
await testPage.getByTestId("settings-index").getByRole("link", { name: "Appearance" }).click();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { expect, test } from "../../fixtures/test-base";
|
||||
import { assertNoDocumentHorizontalOverflow, requireBox } from "../../helpers/layout-assertions";
|
||||
import {
|
||||
captureAppStatusBarSettings,
|
||||
restoreAppStatusBarSettings,
|
||||
@@ -19,7 +20,8 @@ test.describe("Resource metrics display", () => {
|
||||
let baseline: SystemMetricsDisplay;
|
||||
let statusBarBaseline: AppStatusBarSettingsBaseline;
|
||||
|
||||
test.beforeEach(async ({ apiClient }) => {
|
||||
test.beforeEach(async ({ apiClient, testPage }) => {
|
||||
void testPage;
|
||||
const settings = await apiClient.getUserSettings();
|
||||
baseline = settings.settings.system_metrics_display as SystemMetricsDisplay;
|
||||
statusBarBaseline = await captureAppStatusBarSettings(apiClient);
|
||||
@@ -33,6 +35,31 @@ test.describe("Resource metrics display", () => {
|
||||
await restoreAppStatusBarSettings(apiClient, statusBarBaseline);
|
||||
});
|
||||
|
||||
test("keeps detailed desktop metrics in a compact inline status bar", async ({
|
||||
testPage,
|
||||
apiClient,
|
||||
prCapture,
|
||||
}) => {
|
||||
const update = await apiClient.rawRequest("PATCH", "/api/v1/user/settings", {
|
||||
system_metrics_display: { show_in_topbar: true, simplified: false },
|
||||
});
|
||||
expect(update.ok).toBe(true);
|
||||
await testPage.emulateMedia({ colorScheme: "dark" });
|
||||
await testPage.goto("/");
|
||||
const metrics = testPage.getByTestId("app-status-metrics");
|
||||
await expect(metrics.getByLabel(/^CPU /)).toBeVisible();
|
||||
await expect(metrics.getByRole("heading")).toHaveCount(0);
|
||||
const host = await requireBox(metrics.getByLabel("Host metrics"), "host badge");
|
||||
const cpu = await requireBox(metrics.getByLabel(/^CPU /), "CPU reading");
|
||||
expect(Math.abs(host.y + host.height / 2 - cpu.y - cpu.height / 2)).toBeLessThanOrEqual(1);
|
||||
expect((await requireBox(metrics, "desktop metrics")).height).toBeLessThanOrEqual(24);
|
||||
await assertNoDocumentHorizontalOverflow(testPage);
|
||||
if (prCapture.capturing) await expect(testPage.getByTestId("toast-message")).toHaveCount(0);
|
||||
await prCapture.screenshot("system-metrics-desktop", {
|
||||
caption: "Desktop retains the compact inline host metrics in the status bar",
|
||||
});
|
||||
});
|
||||
|
||||
test("renders simplified metrics in the status bar", async ({ testPage }) => {
|
||||
await testPage.goto("/settings/preferences/appearance");
|
||||
const showMetrics = testPage.getByRole("switch", { name: "Show host metrics in status bar" });
|
||||
|
||||
Reference in New Issue
Block a user