From dcee330b5ca984de8657a6d8cf36e34e1d825d4a Mon Sep 17 00:00:00 2001 From: Luke Tornquist Date: Wed, 26 Aug 2026 10:05:01 -0400 Subject: [PATCH] Fix Admin feedback filter overflow (#6825) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why Long community hostnames can make the native Community select exceed the Admin feedback filter grid, pushing the Received and Status controls outside the filter bar and creating horizontal overflow. ## What - Allow filter labels and selects to shrink within their grid tracks - Add a browser regression test covering an unusually long community hostname ## Risk Assessment Low — this is limited to Admin feedback filter sizing and preserves the existing desktop and mobile grid layouts. ## Before The Community select expands past the filter bar and pushes the Received and Status controls outside it. ![Admin feedback filters before the fix](https://raw.githubusercontent.com/block/buzz/f6c2f6d2cb1386feecf4dd6ac2849ab263b1b1a4/pr-6825--01-before.png) ## After Long community names remain contained, keeping all four controls inside the filter bar. ![Admin feedback filters after the fix](https://raw.githubusercontent.com/block/buzz/f6c2f6d2cb1386feecf4dd6ac2849ab263b1b1a4/pr-6825--02-after.png) ## References - Verified on Blox at the local checkout revision: Admin checks passed and all 9 Playwright tests passed Generated with Codex --- admin-web/src/styles.css | 3 ++ admin-web/tests/routes.spec.ts | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/admin-web/src/styles.css b/admin-web/src/styles.css index 93ebceeb14..8f0ba3d6c3 100644 --- a/admin-web/src/styles.css +++ b/admin-web/src/styles.css @@ -195,6 +195,7 @@ h1 { .feedback-filters label { display: grid; gap: 0.45rem; + min-width: 0; } .feedback-filters label > span { @@ -221,6 +222,8 @@ h1 { } .feedback-filters select { + width: 100%; + min-width: 0; padding: 0 2.25rem 0 1rem; } diff --git a/admin-web/tests/routes.spec.ts b/admin-web/tests/routes.spec.ts index 3c965dd2d8..ca6abe7143 100644 --- a/admin-web/tests/routes.spec.ts +++ b/admin-web/tests/routes.spec.ts @@ -224,6 +224,74 @@ test("feedback can be searched and filtered by community and time", async ({ await expect(page.getByText("Calls are much more reliable")).toHaveCount(0); }); +test("feedback filters keep long community names usable", async ({ page }) => { + await page.route("**/api/admin/v1/feedback", (route) => + route.fulfill({ + contentType: "application/json", + body: JSON.stringify([ + { + id: "long-community", + communityId: "long-community", + communityHost: `${"long-community-name.".repeat(4)}buzz.example.com`, + submitterPubkey: "21".repeat(32), + category: "bug", + bodySummary: "The filter row stays within its container", + receivedAt: new Date().toISOString(), + }, + ]), + }), + ); + + for (const viewport of [ + { name: "desktop", width: 1200 }, + { name: "mobile", width: 720 }, + ]) { + await test.step(viewport.name, async () => { + await page.setViewportSize({ width: viewport.width, height: 720 }); + await page.goto("/feedback"); + + const filters = page.locator(".feedback-filters"); + const search = page.getByRole("searchbox", { name: "Search feedback" }); + const community = page.getByRole("combobox", { name: "Community" }); + const status = page.getByLabel("Status"); + await expect(filters).toBeVisible(); + await expect(community).toBeVisible(); + await expect(status).toBeVisible(); + + const [filtersBox, searchBox, communityBox, statusBox] = + await Promise.all([ + filters.boundingBox(), + search.boundingBox(), + community.boundingBox(), + status.boundingBox(), + ]); + if (!filtersBox || !searchBox || !communityBox || !statusBox) { + throw new Error("feedback filter bounds were unavailable"); + } + expect(statusBox.x + statusBox.width).toBeLessThanOrEqual( + filtersBox.x + filtersBox.width, + ); + + if (viewport.name === "desktop") { + const rootFontSize = await page.evaluate(() => + Number.parseFloat( + getComputedStyle(document.documentElement).fontSize, + ), + ); + expect(communityBox.width).toBeGreaterThanOrEqual(14 * rootFontSize); + } else { + expect(Math.abs(communityBox.width - searchBox.width)).toBeLessThan(1); + } + + const pageWidths = await page.evaluate(() => ({ + client: document.documentElement.clientWidth, + scroll: document.documentElement.scrollWidth, + })); + expect(pageWidths.scroll).toBe(pageWidths.client); + }); + } +}); + test("feedback status is stored locally by feedback id", async ({ page }) => { await page.route("**/api/admin/v1/feedback", (route) => route.fulfill({