# UI_DUAL_PANE_DESIGN.md ## Doel van deze notitie Deze notitie beschrijft de ontwerpstap voor **Dual-pane UI v2** op basis van de huidige v1.1 UI en `UI_VISION_MC.md`. Randvoorwaarden voor deze stap: - geen backendwijzigingen - geen nieuwe dependencies - geen multi-select - geen viewer/editor - geen keyboard-uitbreiding (behalve als latere notitie) --- ## 1) Ombouw van single-page UI naar twee panelen ### Huidige situatie (v1.1) - één browsepaneel met één `currentPath` - globale selectie voor dat paneel - acties (mkdir/rename/delete/copy/move) vanuit die ene context ### Doelsituatie (v2) - twee browsepanelen naast elkaar: `left` en `right` - elk paneel heeft: - eigen path input + go - eigen breadcrumbs - eigen directory/file lijst - eigen geselecteerd item - één paneel is altijd **actief** - acties worden contextueel uitgevoerd vanuit actief paneel - tasks- en bookmarks-sectie blijven gedeeld (onder of naast de panelen) ### UI-structuur op hoog niveau - Header: algemene status - Main layout: - Paneel links (`left-pane`) - Paneel rechts (`right-pane`) - Utility-kolom (tasks + bookmarks) - Actieknoppen: - per paneel (mkdir) - actieve-paneelacties (rename/delete/copy/move) ### Bookmark-open gedrag (expliciete keuze) - Een klik op een bookmark opent altijd in het **actieve paneel**. - Motivatie (kort): dit is het meest voorspelbaar, sluit aan op het active/inactive-pane model, en voorkomt verborgen side-effects in het niet-actieve paneel. --- ## 2) Benodigde state per paneel ## State-model ```js state = { panes: { left: { currentPath: "storage1", showHidden: false, selectedItem: null, // { path, name, kind: "file"|"directory" } entries: { directories: [], files: [] } }, right: { currentPath: "storage1", showHidden: false, selectedItem: null, entries: { directories: [], files: [] } } }, activePane: "left", // "left" | "right" selectedTaskId: null, pollHandle: null } ``` ### Verplichte kernstate - `current path` per paneel - `selected item` per paneel - `active pane` globaal ### Afgeleide helperstate - `inactivePane = activePane === "left" ? "right" : "left"` - `canRename/canDelete` op basis van selectie actief paneel - `canCopy/canMove` alleen als selectie actief paneel een file is --- ## 3) Copy/move van actief paneel naar ander paneel ## Semantiek v2 - Bron komt altijd uit `selectedItem` van `activePane`. - Doelcontext is standaard het **andere paneel**. - `destination` blijft volledig doelpad (geen impliciete shell-achtige "copy into" semantics). ### Destination-bepaling - `targetBasePath = panes[inactivePane].currentPath` - `destination = targetBasePath + "/" + sourceItem.name` - UI toont dit voorstel in prompt/confirm en laat aanpassen toe. ### Copy flow 1. User selecteert file in actief paneel. 2. User kiest `Copy`. 3. UI bouwt default destination op basis van inactieve paneel-path + bestandsnaam. 4. UI roept `POST /api/files/copy` met `{source, destination}`. 5. Bij `202`: tasks refresh + taskdetail naar nieuw task_id. 6. Na start: beide panelen refresh (best effort), zodat user contextueel resultaat ziet. ### Move flow 1. Zelfde als copy, maar endpoint `POST /api/files/move`. 2. Bij `202`: tasks refresh + taskdetail selecteren. 3. Beide panelen refreshen (source kan verdwijnen, destination verschijnen). ### Refresh-semantiek per actie (expliciet) - `mkdir`: refresh alleen het actieve paneel. - `rename`: refresh alleen het actieve paneel. - `delete`: refresh alleen het actieve paneel. - `copy`: refresh beide panelen. - `move`: refresh beide panelen. Rationale (kort): - Lokale mutaties (`mkdir/rename/delete`) zijn paneelgebonden en blijven daardoor snel en voorspelbaar. - Transfer-acties (`copy/move`) raken bron- en doelcontext, dus beide panelen verversen voorkomt stale state. ### Foutafhandeling - Validatiefouten vóór task-creatie direct tonen op actiegebied actief paneel. - Runtime-fouten via task-status (`failed`) zichtbaar in tasklijst/detail. --- ## 4) Bestaande backend-endpoints die hergebruikt worden Geen contractwijzigingen; hergebruik van bestaande endpoints: Browse/file ops: - `GET /api/browse` - `POST /api/files/mkdir` - `POST /api/files/rename` - `POST /api/files/delete` - `POST /api/files/copy` - `POST /api/files/move` Tasks: - `GET /api/tasks` - `GET /api/tasks/{task_id}` Bookmarks: - `GET /api/bookmarks` - `POST /api/bookmarks` - `DELETE /api/bookmarks/{bookmark_id}` --- ## 5) Waarschijnlijk te wijzigen bestanden Primair frontend: - `webui/html/index.html` - layout naar dual-pane - pane-specifieke controls/containers - `webui/html/app.js` - state refactor naar `panes.left/right` - browse/render/actions per pane - active-pane switching - copy/move destination vanuit ander pane - `webui/html/style.css` - twee panelen visueel gelijkwaardig - actieve-paneel-highlight - responsieve fallback (mobiel: gestapeld) Tests: - `webui/backend/tests/golden/test_ui_smoke_golden.py` - assertions bijwerken naar dual-pane markup/ids Niet gepland in deze stap: - backend python-bestanden - API schemas/routes/services --- ## 6) Regressierisico ## Hoog risico - Stateverwarring tussen links/rechts paneel (actie op verkeerde paneelcontext). - Onjuiste destination-opbouw bij copy/move (per ongeluk vanuit actief i.p.v. inactief pad). ## Middel risico - Disable/enable logica van knoppen niet synchroon met actieve paneelselectie. - Refresh-volgorde na acties waardoor UI tijdelijk stale data toont. - Bookmarks die per ongeluk in het verkeerde paneel openen als `activePane` niet consequent wordt gebruikt. ## Laag risico - CSS regressies in mobile layout. - Kleine tekst/label inconsistenties in error/statusweergave. ## Mitigatie - Duidelijke pane-identifiers in DOM en handlers (`left`/`right`). - Eén centrale helper voor `getActivePane()` en `getInactivePane()`. - Eén centrale helper voor copy/move destination-opbouw. - Smoke tests expliciet op dual-pane hoofdstructuur. --- ## 7) Aan te passen/toe te voegen UI smoke tests ## Aanpassen bestaande smoke test `test_ui_smoke_golden.py`: - huidige checks op enkel browsepaneel vervangen door dual-pane checks. Nieuwe/gewijzigde assertions: - UI mount bestaat op `/ui`. - HTML bevat beide hoofdpanelen: - `id="left-pane"` - `id="right-pane"` - HTML bevat actieve-paneel-indicator/container (bijv. class of data-attribute). - Assets blijven gemapt: - `/ui/app.js` - `/ui/style.css` ## Kleine extra smoke checks (zonder backenduitbreiding) - basisactieknoppen aanwezig voor actieve-paneelacties. - tasks- en bookmarks-panelen blijven aanwezig in HTML. Geen end-to-end browserautomatisering in deze stap. --- ## Niet in scope voor deze implementatieslice - multi-select - viewer/editor - cancel/retry - history UI - nieuwe backend endpoints - keyboard mapping uitbreiding (eventueel later)