From 21bac11aa5c5e6738e578bf19aa2973e58851b0b Mon Sep 17 00:00:00 2001 From: riyadhafraa <49757212-riyadhafraa@users.noreply.replit.com> Date: Mon, 11 May 2026 08:05:51 +0000 Subject: [PATCH] #485 Fix overlapping layout in the Postpone meeting dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Arabic/RTL the Postpone dialog (opened from the upcoming-meeting alert) was visibly overlapping its own borders on two tabs: 1. Postpone tab → cascade preview ("الاجتماعات المتأثرة"): the times column ran wider than the pink panel, the title column pushed it off-screen, and the meeting-# header wrapped to two lines while the others stayed on one. 2. Reschedule tab: three native date / start / end inputs forced into md:grid-cols-3 inside an sm:max-w-md dialog, which clipped the right-most input against the dialog frame in RTL. Both issues were pure layout — the dialog was simply too narrow for its content. Changes (artifacts/tx-os/src/components/executive-meetings/upcoming-meeting-alert.tsx): - Bumped the postpone DialogContent from `sm:max-w-md` (≈448 px) to `sm:max-w-2xl` (≈672 px). Still full width on phones, capped on desktop. Reschedule's existing `grid-cols-1 sm:grid-cols-2 md:grid-cols-3` now has room to actually render three inputs at md without clipping (Input already defaults to w-full). - CascadePromptBlock affected-meetings table: switched to `table-fixed` with an explicit `` (w-12 number / flex title / w-40 times). Title cell keeps its `truncate` + `title=` tooltip but no longer needs `max-w-[180px]`. Added `whitespace-nowrap` to # and times headers so the latter never wraps. Wrapper got `overflow-x-hidden` to belt-and-suspenders the no-horizontal-scroll guarantee. Action button row already used `flex-wrap` — preserved. Tests (artifacts/tx-os/tests/executive-meetings-upcoming-alert.spec.mjs): - Added a regression test that opens the dialog at 1280×800 in Arabic, switches to the Reschedule tab, and asserts the bounding boxes of `reschedule-date` / `reschedule-start` / `reschedule-end` all sit inside the dialog's bounding box (1 px tolerance). - Re-ran the full upcoming-alert spec to confirm no behavior regressions in postpone-by-minutes, cascade prompts, cancel, reschedule-to-tomorrow, dismiss, or the alert position-clamp test. Out of scope (per task spec): backend cascade/postpone logic, the floating alert panel itself, dialog visual restyling, and the Cancel tab beyond what comes "for free" with the wider dialog. The pre-existing `test` workflow failures (executive-meetings reorder, font-settings roundtrip, notes-share recipient PATCH 403/404) are unrelated to this layout change and were already failing before. --- .../upcoming-meeting-alert.tsx | 21 +++++++--- ...executive-meetings-upcoming-alert.spec.mjs | 40 +++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/artifacts/tx-os/src/components/executive-meetings/upcoming-meeting-alert.tsx b/artifacts/tx-os/src/components/executive-meetings/upcoming-meeting-alert.tsx index 147244bf..9f042832 100644 --- a/artifacts/tx-os/src/components/executive-meetings/upcoming-meeting-alert.tsx +++ b/artifacts/tx-os/src/components/executive-meetings/upcoming-meeting-alert.tsx @@ -948,20 +948,29 @@ function CascadePromptBlock({ {/* #481: 3-column table (Meeting #, Title, From → To) so the user can scan affected meetings by their meeting-of-the-day number alongside the title and the projected time shift. */} -
+
+ {/* #485: explicit colgroup so the meeting-# header doesn't + wrap to two lines, the title column truncates with an + ellipsis instead of pushing the times off-screen, and + the From → To column always fits on one line. */} + + + + + - - @@ -979,7 +988,7 @@ function CascadePromptBlock({ -
+ {t("executiveMeetings.alert.cascadeColMeetingNumber")} {t("executiveMeetings.alert.cascadeColTitle")} + {t("executiveMeetings.alert.cascadeColTimes")}
{dn != null ? dn : "—"} + {title} @@ -1441,7 +1450,7 @@ function PostponeDialog({ diff --git a/artifacts/tx-os/tests/executive-meetings-upcoming-alert.spec.mjs b/artifacts/tx-os/tests/executive-meetings-upcoming-alert.spec.mjs index 19dcbb9d..6e993ec7 100644 --- a/artifacts/tx-os/tests/executive-meetings-upcoming-alert.spec.mjs +++ b/artifacts/tx-os/tests/executive-meetings-upcoming-alert.spec.mjs @@ -1290,3 +1290,43 @@ test("Upcoming-meeting alert: details panel renders attendees as numbered tables await expect(secondGroupRows.first()).toContainText("1."); await expect(secondGroupRows.first()).toContainText("Internal One"); }); + +test("Postpone dialog: reschedule date / start / end inputs sit fully inside the dialog (no clipping at desktop width, RTL)", async ({ + page, +}) => { + // #485: regression for the layout overlap reported in Arabic. The + // postpone dialog used to be sm:max-w-md (~448px) which clipped the + // 3-column native date/time row against the dialog border in RTL. + // After widening the dialog and tightening the column widths, every + // input's bounding box must lie inside the dialog's bounding box. + await setLang(page, "ar"); + await insertImminentMeeting({ + titleAr: `${TEST_TAG} layout AR`, + titleEn: `${TEST_TAG} layout EN`, + deltaMins: 3, + }); + await page.setViewportSize({ width: 1280, height: 800 }); + await loginViaUi(page, "admin", "admin123"); + await page.goto("/"); + await expect(page.getByTestId("upcoming-meeting-alert")).toBeVisible({ + timeout: 15_000, + }); + await page.getByTestId("alert-postpone").click(); + const dialog = page.getByTestId("postpone-dialog"); + await expect(dialog).toBeVisible(); + await page.getByTestId("postpone-tab-reschedule").click(); + await expect(page.getByTestId("postpone-reschedule-panel")).toBeVisible(); + + const dialogBox = await dialog.boundingBox(); + expect(dialogBox).not.toBeNull(); + for (const tid of ["reschedule-date", "reschedule-start", "reschedule-end"]) { + const inputBox = await page.getByTestId(tid).boundingBox(); + expect(inputBox, `${tid} should have a bounding box`).not.toBeNull(); + // Inputs must sit fully within the dialog (small 1px tolerance for + // sub-pixel rounding from native controls). + expect(inputBox.x + 1).toBeGreaterThanOrEqual(dialogBox.x); + expect(inputBox.x + inputBox.width).toBeLessThanOrEqual( + dialogBox.x + dialogBox.width + 1, + ); + } +});