From 342ad314894fe2a009d83039931ae4235fd3f157 Mon Sep 17 00:00:00 2001 From: maziggy Date: Fri, 5 Jun 2026 10:52:10 +0200 Subject: [PATCH] fix(projects): make edit modal scrollable so Save is reachable on short screens (#1642) Reporter on a 1508x831 Pi display couldn't mark a project as Completed because the edit modal's height exceeded the viewport: the outer wrapper centers vertically and the inner card had no max-h and no overflow, so the top half scrolled above and the bottom half (Status dropdown + Save/Cancel) scrolled below. Workaround was a full page reload. Standard flex-modal-scroll fix: max-h-[calc(100vh-2rem)] + flex flex-col on the card; a flex-1 overflow-y-auto min-h-0 wrapper around the form fields; Cancel/Save moved into a flex-shrink-0 sibling with a border-t separator so they're always visible regardless of scroll position. Buttons stay inside
so type="submit" still works. --- CHANGELOG.md | 3 + .../src/__tests__/pages/ProjectsPage.test.tsx | 76 ++++++++++++++++++- frontend/src/pages/ProjectsPage.tsx | 16 +++- .../{index-DrAXd6Gv.js => index-CyGvoJrx.js} | 2 +- static/index.html | 2 +- 5 files changed, 92 insertions(+), 7 deletions(-) rename static/assets/{index-DrAXd6Gv.js => index-CyGvoJrx.js} (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 577fee919..f524135a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to Bambuddy will be documented in this file. ## [0.2.5b1] - Unreleased +### Fixed +- **Project edit modal couldn't be scrolled, so Save / Cancel were unreachable on short screens (#1642, reported by @klevin92)** — Reporter on a Pi-class display (1508 × 831) couldn't mark a project as Completed because the edit modal's height exceeded the viewport and there was no way to scroll: outer wrapper was `fixed inset-0 flex items-center justify-center p-4` (vertical-center) and the inner card had no `max-h` and no `overflow`. The top of the form went above the viewport and the bottom — including the Status dropdown the reporter was trying to use plus both action buttons — went below it. Workaround was a full page reload to drop the modal. Standard flex-modal-scroll fix: `max-h-[calc(100vh-2rem)]` + `flex flex-col` on the card (the `2rem` accounts for the outer `p-4`), a `flex-1 overflow-y-auto min-h-0` wrapper around the form fields, and the Cancel / Save buttons moved into a `flex-shrink-0` sibling with a `border-t` separator so they become a sticky footer that's always visible regardless of scroll position. The buttons stay inside the `` so `type="submit"` still works. 2 new vitest cases in `ProjectsPage.test.tsx` pin the structural fix: the Save button is NOT a descendant of the `overflow-y-auto` region (otherwise it would scroll off again) and the modal card carries the `max-h-[calc(100vh-2rem)]` cap. Other modals in the codebase with the same `fixed inset-0 flex items-center justify-center` + `max-w-md` shape almost certainly have the same latent bug — not refactored here, will tackle when reported. + ### Changed - **File Manager sidebar: "All Files" now scopes to your own uploaded files; new "External" entry holds the combined linked-folder view (#1621, reported by @kcw96)** — Reporter linked a NAS share that auto-imported hundreds of 3MFs, and from then on their handful of Bambuddy-uploaded files was lost in the "All Files" listing — no filter, no toggle, only per-folder clicks to escape the noise. Restored the pre-external semantics so long-time users get their muscle memory back: "All Files" lists managed-storage files only (`is_external=False`), exactly what it meant before external folders existed. The combined "everything across every external mount" view moves to a new sibling sidebar entry, **External**, which only renders when at least one external folder is linked (zero-cost on installs that don't use the feature). Per-folder clicking is unchanged: clicking any folder in the tree — internal or external — still shows that folder's contents directly. **Backend**: `/api/v1/library/files` gains two mutually-exclusive query flags, `internal_only` and `external_only`, filtering directly on `LibraryFile.is_external`. Both-flags-set is a 400 (catches frontend regressions immediately instead of silently picking one). Folder- or project-scoped requests bypass both flags because they already imply a single scope. **Frontend**: new `topLevelView: 'internal' | 'external'` state on `FileManagerPage`, default `internal`; the query passes the corresponding scope only when `selectedFolderId === null`. Sidebar shows the "External" row gated on `folders.some(f => f.is_external)`; mobile selector dropdown carries a `__top:internal` / `__top:external` sentinel so the same state can round-trip through `