234 lines
6.7 KiB
Markdown
234 lines
6.7 KiB
Markdown
# 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)
|