fix mobile overflowing icons in system due to new health pane

This commit is contained in:
Josh Hawkins
2026-09-18 06:55:55 -05:00
parent e24bb8be72
commit 9ab0d97278
2 changed files with 86 additions and 30 deletions
+49
View File
@@ -72,7 +72,15 @@ test.describe("System — tabs @medium", () => {
{ timeout: 15_000 }, { timeout: 15_000 },
); );
await expect(frigateApp.page.getByText("0.15.0-test")).toBeVisible(); await expect(frigateApp.page.getByText("0.15.0-test")).toBeVisible();
if (frigateApp.isMobile) {
// the "Last refreshed" label is dropped on mobile so the timestamp
// clears the centered logo
await expect(frigateApp.page.getByText(/Last refreshed/)).toHaveCount(0);
await expect(frigateApp.page.getByText(/Just now|ago/)).toBeVisible();
} else {
await expect(frigateApp.page.getByText(/Last refreshed/)).toBeVisible(); await expect(frigateApp.page.getByText(/Last refreshed/)).toBeVisible();
}
}); });
test("storage tab renders content after switching", async ({ test("storage tab renders content after switching", async ({
@@ -234,4 +242,45 @@ test.describe("System — mobile @medium @mobile", () => {
{ timeout: 5_000 }, { timeout: 5_000 },
); );
}); });
test("header controls leave the logo uncovered on a narrow phone", async ({
frigateApp,
}) => {
await frigateApp.goto("/system#general");
await expect(frigateApp.page.getByLabel("Select general")).toHaveAttribute(
"data-state",
"on",
{ timeout: 15_000 },
);
await frigateApp.page.setViewportSize({ width: 320, height: 740 });
const logo = frigateApp.page.locator("svg.fill-current").first();
const tabs = frigateApp.page
.locator("[data-radix-scroll-area-viewport]")
.filter({ has: frigateApp.page.getByLabel("Select general") });
const refreshed = frigateApp.page.getByText(/Just now|ago/);
const logoBox = await logo.boundingBox();
const tabsBox = await tabs.boundingBox();
const refreshedBox = await refreshed.boundingBox();
expect(tabsBox!.x + tabsBox!.width).toBeLessThanOrEqual(logoBox!.x + 1);
expect(refreshedBox!.x).toBeGreaterThanOrEqual(logoBox!.x + logoBox!.width);
// the clipped tabs stay reachable by scrolling
const overflow = await tabs.evaluate((el) => ({
scroll: el.scrollWidth,
client: el.clientWidth,
}));
expect(overflow.scroll).toBeGreaterThan(overflow.client);
await tabs.evaluate((el) => {
el.scrollLeft = el.scrollWidth;
});
await frigateApp.page.getByLabel("Select cameras").click();
await expect(frigateApp.page.getByLabel("Select cameras")).toHaveAttribute(
"data-state",
"on",
{ timeout: 5_000 },
);
});
}); });
+8 -1
View File
@@ -24,6 +24,8 @@ import HealthMetrics from "@/views/system/HealthMetrics";
import NoticeFilterButton from "@/components/health/NoticeFilterButton"; import NoticeFilterButton from "@/components/health/NoticeFilterButton";
import { DEFAULT_NOTICE_FILTER, NoticeFilter } from "@/types/health"; import { DEFAULT_NOTICE_FILTER, NoticeFilter } from "@/types/health";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
const allMetrics = [ const allMetrics = [
"health", "health",
@@ -96,6 +98,8 @@ function System() {
{isMobile && ( {isMobile && (
<Logo className="absolute inset-x-1/2 h-8 -translate-x-1/2" /> <Logo className="absolute inset-x-1/2 h-8 -translate-x-1/2" />
)} )}
<ScrollArea className={cn("whitespace-nowrap", isMobile && "w-[45%]")}>
<div className="flex flex-row">
<ToggleGroup <ToggleGroup
className="*:rounded-md *:px-3 *:py-4" className="*:rounded-md *:px-3 *:py-4"
type="single" type="single"
@@ -125,6 +129,9 @@ function System() {
</ToggleGroupItem> </ToggleGroupItem>
))} ))}
</ToggleGroup> </ToggleGroup>
<ScrollBar orientation="horizontal" className="h-0" />
</div>
</ScrollArea>
<div className="flex h-full items-center"> <div className="flex h-full items-center">
{pageToggle == "health" && ( {pageToggle == "health" && (
@@ -135,7 +142,7 @@ function System() {
)} )}
{lastUpdated && pageToggle != "health" && ( {lastUpdated && pageToggle != "health" && (
<div className="h-full content-center text-sm text-muted-foreground"> <div className="h-full content-center text-sm text-muted-foreground">
{t("lastRefreshed")} {isDesktop && t("lastRefreshed")}
<TimeAgo time={lastUpdated * 1000} dense /> <TimeAgo time={lastUpdated * 1000} dense />
</div> </div>
)} )}