Volumes
This commit is contained in:
@@ -0,0 +1,259 @@
|
||||
# UI_F6_RENAME_MOVE_DESIGN.md
|
||||
|
||||
## 1. Doel
|
||||
|
||||
Deze stap herontwerpt `F6` naar een gecombineerde `Rename/Move` actie in Midnight Commander-stijl.
|
||||
|
||||
Doel:
|
||||
- `F6` wordt de primaire actie voor zowel hernoemen als verplaatsen
|
||||
- de gebruiker werkt vanuit één compacte flow in plaats van aparte shortcuts
|
||||
- een losse `Rename` shortcut zoals `Alt+R` is daarna niet meer gewenst
|
||||
|
||||
Uitgangspunt:
|
||||
- de functiebalk kan `Rename` visueel nog blijven tonen als aparte knop, maar de keyboardflow voor `F6` wordt leidend voor gecombineerde rename/move-semantiek
|
||||
- deze ontwerpstap verandert nog niets aan backendcontracten
|
||||
|
||||
---
|
||||
|
||||
## 2. Popupgedrag
|
||||
|
||||
Bij `F6` opent de UI een compacte popup.
|
||||
|
||||
Popup-eisen:
|
||||
- één invoerveld
|
||||
- één contextregel met bronbestand/-map
|
||||
- één invoerveld met voorgesteld doelpad
|
||||
- compacte actieknoppen: `OK` en `Cancel` zijn optioneel, maar `Enter` en `Escape` zijn leidend
|
||||
|
||||
Keyboardgedrag:
|
||||
- `Escape` sluit popup zonder actie
|
||||
- `Enter` voert de actie uit
|
||||
|
||||
Semantiek:
|
||||
- popup is niet alleen een naamveld, maar een doelpadveld
|
||||
- gebruiker kan dus zowel alleen de naam aanpassen als een volledig ander doelpad kiezen
|
||||
|
||||
---
|
||||
|
||||
## 3. Defaultwaarde in het invoerveld
|
||||
|
||||
De standaardwaarde in het invoerveld wordt:
|
||||
|
||||
- `current path` van het **andere paneel**
|
||||
- plus de huidige naam van het geselecteerde bestand of de geselecteerde map
|
||||
|
||||
Voorbeeld:
|
||||
- actief paneel: `left`
|
||||
- geselecteerd item: `storage1/docs/report.txt`
|
||||
- inactief paneel current path: `storage2/archive`
|
||||
- default invoerveld:
|
||||
- `storage2/archive/report.txt`
|
||||
|
||||
Motivatie:
|
||||
- dit past bij klassieke dual-pane file-managerverwachting: `F6` suggereert standaard verplaatsen naar de andere kant
|
||||
- dezelfde popup blijft bruikbaar voor pure rename door het doelpad handmatig terug te brengen naar dezelfde parent met een andere naam
|
||||
|
||||
Belangrijk:
|
||||
- de default is altijd een **volledig doelpad**
|
||||
- geen impliciete "move into current dir" semantiek buiten wat in het tekstveld staat
|
||||
|
||||
---
|
||||
|
||||
## 4. Beslislogica
|
||||
|
||||
De UI bepaalt op basis van bronpad en ingevoerd doelpad of de actie neerkomt op `rename` of `move`.
|
||||
|
||||
### Regel 1: zelfde parent, andere naam = rename
|
||||
|
||||
Als:
|
||||
- bron en doel in dezelfde parent-directory liggen
|
||||
- en alleen de naam verschilt
|
||||
|
||||
dan gebruikt de UI het bestaande `rename` endpoint.
|
||||
|
||||
Voorbeeld:
|
||||
- bron: `storage1/docs/report.txt`
|
||||
- doel: `storage1/docs/report-final.txt`
|
||||
- resultaat: `rename`
|
||||
|
||||
### Regel 2: ander pad of andere parent = move
|
||||
|
||||
Als:
|
||||
- de doel-parent verschilt van de bron-parent
|
||||
- of de doel-root/paneelcontext anders is
|
||||
|
||||
dan gebruikt de UI het bestaande `move` endpoint.
|
||||
|
||||
Voorbeeld:
|
||||
- bron: `storage1/docs/report.txt`
|
||||
- doel: `storage2/archive/report.txt`
|
||||
- resultaat: `move`
|
||||
|
||||
### Regel 3: ongewijzigde waarde = move naar andere paneel-locatie
|
||||
|
||||
Omdat de defaultwaarde standaard naar het andere paneel wijst, betekent ongewijzigd bevestigen normaal gesproken:
|
||||
- `move` naar het current path van het andere paneel met dezelfde naam
|
||||
|
||||
Voorbeeld:
|
||||
- bron: `storage1/docs/report.txt`
|
||||
- default doel: `storage2/archive/report.txt`
|
||||
- gebruiker drukt direct `Enter`
|
||||
- resultaat: `move`
|
||||
|
||||
### Regel 4: exact gelijk aan bronpad = no-op
|
||||
|
||||
Als de gebruiker het invoerveld wijzigt naar exact hetzelfde pad als de bron:
|
||||
- er wordt geen rename of move gestart
|
||||
- de popup sluit niet automatisch met een schijnactie
|
||||
- voorkeur v1: compacte validatiemelding zoals `Destination must differ from source`
|
||||
|
||||
Dit voorkomt zinloze requests.
|
||||
|
||||
---
|
||||
|
||||
## 5. Relatie met huidige backend
|
||||
|
||||
### Rename endpoint
|
||||
|
||||
Te gebruiken als de UI beslist op `rename`:
|
||||
- `POST /api/files/rename`
|
||||
|
||||
Mapping:
|
||||
- request gebruikt bestaand model:
|
||||
- `path = source`
|
||||
- `new_name = basename(destination)`
|
||||
|
||||
Belangrijke beperking:
|
||||
- bestaand rename-contract werkt alleen binnen dezelfde parent-directory
|
||||
- de UI moet dat contract respecteren en alleen in die situatie `rename` gebruiken
|
||||
|
||||
### Move endpoint
|
||||
|
||||
Te gebruiken als de UI beslist op `move`:
|
||||
- `POST /api/files/move`
|
||||
|
||||
Mapping:
|
||||
- request gebruikt bestaand model:
|
||||
- `source`
|
||||
- `destination` als volledig doelpad
|
||||
|
||||
### File versus directory
|
||||
|
||||
Huidige backend-scope blijft leidend:
|
||||
- `rename` ondersteunt bestaande rename-semantiek op file/directory zoals nu aanwezig
|
||||
- `move` is momenteel file-only
|
||||
|
||||
Gevolg voor gecombineerde F6-flow:
|
||||
- file + ander pad -> `move` toegestaan
|
||||
- file + zelfde parent andere naam -> `rename` toegestaan
|
||||
- directory + zelfde parent andere naam -> `rename` toegestaan
|
||||
- directory + ander pad -> niet toegestaan zolang backend directory-move niet ondersteunt
|
||||
|
||||
Voor directory-case buiten scope:
|
||||
- de popup mag wel openen
|
||||
- maar bevestigen moet blokkeren met duidelijke melding, bijvoorbeeld:
|
||||
- `Directory move is not supported in v1`
|
||||
|
||||
### Huidige scopebeperkingen blijven gelden
|
||||
|
||||
Dus expliciet:
|
||||
- geen directory move
|
||||
- geen batch rename/move via deze popup in v1
|
||||
- geen backend-uitbreiding om F6 slimmer te maken
|
||||
- alle padvalidatie en foutafhandeling blijven backendgedreven
|
||||
|
||||
---
|
||||
|
||||
## 6. Focus en UX
|
||||
|
||||
Popup-eisen:
|
||||
- compact en centraal
|
||||
- niet schermvullend
|
||||
- focus direct in het invoerveld
|
||||
- volledige doelpadtekst selecteerbaar en bewerkbaar
|
||||
|
||||
Keyboardgedrag:
|
||||
- `Enter` = bevestigen
|
||||
- `Escape` = annuleren
|
||||
|
||||
Interactie-eis:
|
||||
- terwijl de popup open is, mag paneelkeyboardnavigatie niet interfereren
|
||||
- bestaande shortcuts voor paneelnavigatie en functiebalkacties moeten tijdelijk uitgeschakeld zijn, behalve popup-eigen `Enter`/`Escape`
|
||||
|
||||
Feedback:
|
||||
- validatiefouten compact in de popup tonen
|
||||
- backendfouten terugkoppelen zonder de popup-context te verliezen als de actie faalt
|
||||
|
||||
---
|
||||
|
||||
## 7. Scopebeperking
|
||||
|
||||
Niet in deze stap:
|
||||
- geen implementatie
|
||||
- geen backendwijzigingen
|
||||
- geen nieuwe dependencies
|
||||
- geen directory move ondersteuning
|
||||
- geen multi-select rename/move popup
|
||||
- geen extra path picker of browse-in-dialog
|
||||
|
||||
Deze ontwerpstap beperkt zich dus tot de UI-semantiek van één gecombineerde `F6` flow.
|
||||
|
||||
---
|
||||
|
||||
## 8. Impactanalyse
|
||||
|
||||
Waarschijnlijk te wijzigen frontendbestanden bij implementatie:
|
||||
- `webui/html/app.js`
|
||||
- `webui/html/index.html`
|
||||
- `webui/html/style.css`
|
||||
- `webui/backend/tests/golden/test_ui_smoke_golden.py`
|
||||
|
||||
### Verwachte aanpassingen
|
||||
|
||||
`app.js`:
|
||||
- nieuwe popup-state voor F6 rename/move
|
||||
- beslislogica `rename` versus `move`
|
||||
- verwijdering of aanpassing van losse `Alt+R` keyboardbinding
|
||||
- hergebruik van bestaande rename- en move-action handlers waar mogelijk
|
||||
|
||||
`index.html`:
|
||||
- compacte popup-markup met invoerveld en foutregel
|
||||
|
||||
`style.css`:
|
||||
- compacte popup-styling, aansluitend op bestaande wildcard/view/edit modals
|
||||
|
||||
### Regressierisico
|
||||
|
||||
Belangrijkste risico's:
|
||||
- verwarring tussen bestaande losse `Rename` knop en nieuwe F6-semantiek
|
||||
- directorycases die per ongeluk op `move` uitkomen terwijl backend dat niet ondersteunt
|
||||
- dubbele logica tussen functiebalk-`Rename`, functiebalk-`Move` en F6-popup
|
||||
- keyboardconflict met bestaande `F6 = Move` shortcut uit action-shortcuts v1
|
||||
|
||||
Mitigatie:
|
||||
- één centrale beslisfunctie voor `rename` versus `move`
|
||||
- `Alt+R` verwijderen zodra F6-flow geïmplementeerd wordt
|
||||
- bestaande knophandlers alleen hergebruiken waar de semantiek echt gelijk is; anders kleine centrale wrapperfunctie introduceren
|
||||
|
||||
---
|
||||
|
||||
## 9. Teststrategie
|
||||
|
||||
### Smoke/regressietests
|
||||
|
||||
Bij implementatie aan te passen:
|
||||
- UI smoke test controleert aanwezigheid van F6 popup-container
|
||||
- controle op relevant inputveld en basiscontrols
|
||||
- bestaande functiebalk- en modalchecks blijven bestaan
|
||||
|
||||
### Handmatige validatie
|
||||
|
||||
Essentieel:
|
||||
- `F6` opent popup met defaultwaarde gebaseerd op ander paneel + huidige naam
|
||||
- `Enter` met default leidt tot `move`
|
||||
- wijziging naar zelfde parent + andere naam leidt tot `rename`
|
||||
- directory + cross-path wordt netjes geblokkeerd
|
||||
- `Escape` sluit popup zonder bijeffecten
|
||||
- paneelkeyboardnavigatie werkt niet door popup heen
|
||||
- bestaande `Move` knop blijft werken
|
||||
- bestaande `Rename` knop blijft werken totdat eventuele latere UI-consolidatie expliciet wordt doorgevoerd
|
||||
@@ -0,0 +1,151 @@
|
||||
# UI_VOLUMES_DIRECTORY_VIEW_V1
|
||||
|
||||
## 1. Doel
|
||||
|
||||
Doel van deze stap is om de webui een host-achtige navigatiestructuur te geven waarbij de gebruiker eerst `/Volumes` ziet en daarna daarbinnen de beschikbare mounts kan openen, zoals:
|
||||
|
||||
- `/Volumes/8TB`
|
||||
- `/Volumes/8TB_RAID1`
|
||||
|
||||
Waarom dit gewenst is:
|
||||
- het sluit beter aan op de werkelijke host- en containerstructuur
|
||||
- het voorkomt dat technische aliasnamen zoals `storage1` en `storage2` het primaire navigatiemodel bepalen
|
||||
- het maakt de UI begrijpelijker voor gebruikers die denken in echte mountpunten en directories, niet in app-specifieke labels
|
||||
|
||||
---
|
||||
|
||||
## 2. Gewenste UI-weergave
|
||||
|
||||
Gewenst gedrag in beide panelen:
|
||||
- een paneel kan op `/Volumes` staan als huidige directoryweergave
|
||||
- in die weergave ziet de gebruiker de toegestane submappen als normale directory entries
|
||||
- voor deze case moeten daar minimaal zichtbaar zijn:
|
||||
- `8TB`
|
||||
- `8TB_RAID1`
|
||||
|
||||
Navigatieflow:
|
||||
- gebruiker opent of kiest `/Volumes`
|
||||
- de lijst toont `8TB` en `8TB_RAID1` als directories
|
||||
- klikken of `Enter` op `8TB` opent `/Volumes/8TB`
|
||||
- klikken of `Enter` op `8TB_RAID1` opent `/Volumes/8TB_RAID1`
|
||||
|
||||
Voor dual-pane gedrag:
|
||||
- beide panelen moeten onafhankelijk op `/Volumes` of op een onderliggende mount kunnen staan
|
||||
- er is geen speciaal verschillend gedrag nodig tussen links en rechts
|
||||
- breadcrumbs moeten `/Volumes` en daarna de mountnaam tonen
|
||||
|
||||
---
|
||||
|
||||
## 3. Relatie met huidige whitelist/root-configuratie
|
||||
|
||||
Huidige situatie:
|
||||
- de backend werkt met expliciete toegestane roots via aliases
|
||||
- defaults zijn nu:
|
||||
- `storage1 -> /Volumes/8TB`
|
||||
- `storage2 -> /Volumes/8TB_RAID1`
|
||||
|
||||
Belangrijk verschil:
|
||||
- de huidige whitelist geeft alleen directe toegang tot specifieke roots
|
||||
- `/Volumes` zelf is op dit moment conceptueel geen browsebare root in het bestaande model
|
||||
|
||||
Voor het gewenste gedrag is een extra browsebaar niveau nodig:
|
||||
- niet als volledig vrije root over het hele filesystem
|
||||
- maar als gecontroleerde containerdirectory die alleen als bovenliggende presentatie-laag dient voor de whitelisted mounts
|
||||
|
||||
Cruciale eis:
|
||||
- als `/Volumes` zichtbaar wordt, mag niet automatisch alle andere inhoud van `/Volumes` browsebaar worden
|
||||
- alleen de expliciet toegestane mounts onder `/Volumes` mogen zichtbaar zijn
|
||||
|
||||
---
|
||||
|
||||
## 4. Veiligheidsmodel
|
||||
|
||||
Aanbevolen veiligheidsmodel:
|
||||
- `/Volumes` wordt niet behandeld als een normale vrije root
|
||||
- `/Volumes` wordt behandeld als een virtuele of gecontroleerde container-directoryweergave boven de bestaande whitelisted roots
|
||||
|
||||
Veilige semantiek:
|
||||
- de UI/backend toont in `/Volumes` alleen de mountnamen die corresponderen met toegestane roots
|
||||
- voor deze case dus alleen:
|
||||
- `8TB`
|
||||
- `8TB_RAID1`
|
||||
- andere directories onder de echte `/Volumes` mogen niet automatisch zichtbaar worden
|
||||
|
||||
Concreet:
|
||||
- browse van `/Volumes` retourneert een samengestelde directorylisting op basis van toegestane roots
|
||||
- navigatie naar `/Volumes/<naam>` is alleen geldig als die volledige path overeenkomt met een geconfigureerde root of daarbinnen valt
|
||||
|
||||
Passend bij bestaand model:
|
||||
- alle verdere padresolutie onder `/Volumes/8TB/...` en `/Volumes/8TB_RAID1/...` blijft via bestaand `path_guard`
|
||||
- traversal en whitelistcontrole blijven dus centraal gehandhaafd
|
||||
|
||||
---
|
||||
|
||||
## 5. Backend-impact
|
||||
|
||||
Dit kan niet netjes alleen frontend-side worden opgelost.
|
||||
|
||||
Waarom niet frontend-only:
|
||||
- de bestaande browse-API verwacht een pad dat door de backend gevalideerd en opgelijst wordt
|
||||
- als de backend `/Volumes` niet kent als geldige browsecontext, kan de frontend die laag niet betrouwbaar simuleren zonder speciale hardcoded clientlogica
|
||||
- frontend-only zou ook de securitygrenzen vertroebelen, omdat de UI dan zelf een deel van de directorystructuur zou moeten faken
|
||||
|
||||
Backend-aanpassing is dus nodig.
|
||||
|
||||
Veiligste en simpelste richting:
|
||||
- een kleine backend-uitbreiding in de browse-service/path-interpretatie
|
||||
- introduceer een gecontroleerd browse-niveau voor `/Volumes`
|
||||
- behandel dat niveau als speciale, beperkte listing van geconfigureerde roots
|
||||
- behoud voor alle onderliggende operaties het bestaande whitelist/path_guard-model
|
||||
|
||||
Pragmatische v1-richting:
|
||||
- voeg een expliciete conceptuele container-root toe, bijvoorbeeld browsepad `/Volumes`
|
||||
- browse op `/Volumes` retourneert alleen directory-entries voor de toegestane mount-roots
|
||||
- browse op `/Volumes/<mount>` mapt naar de bestaande geconfigureerde root
|
||||
|
||||
Dat is veiliger dan `/Volumes` volledig als nieuwe whitelist-root toevoegen.
|
||||
|
||||
---
|
||||
|
||||
## 6. Risico's
|
||||
|
||||
### Regressierisico
|
||||
- browse-contract moet duidelijk blijven voor bestaande paden zoals `storage1/...`
|
||||
- bestaande UI- en golden-tests zijn nu alias-gebaseerd; die mogen niet onbedoeld breken
|
||||
- copy/move/rename/delete/bookmarks werken nu op bestaande padrepresentaties; migratie naar `/Volumes/...` moet doordacht gebeuren
|
||||
|
||||
### Securitygevolgen
|
||||
- een onzorgvuldige implementatie zou per ongeluk meer van `/Volumes` kunnen tonen dan toegestaan
|
||||
- een onzorgvuldige mapping van `/Volumes/<naam>` naar echte paden kan whitelistcontroles verzwakken
|
||||
|
||||
### UX-verwarring
|
||||
- tijdelijke co-existentie van aliaspaden (`storage1/...`) en hostachtige paden (`/Volumes/8TB/...`) kan verwarrend zijn
|
||||
- zonder heldere keuze ontstaat een hybride model dat lastig te begrijpen en te testen is
|
||||
|
||||
---
|
||||
|
||||
## 7. Aanbeveling
|
||||
|
||||
Aanbevolen implementatierichting voor v1:
|
||||
|
||||
1. Niet frontend-only doen.
|
||||
2. Geen vrije browse-root van heel `/Volumes` toevoegen.
|
||||
3. Wel een gecontroleerde backend-browseweergave voor `/Volumes` introduceren.
|
||||
4. Laat die weergave alleen expliciet geconfigureerde mountdirectories tonen.
|
||||
5. Houd alle echte padvalidatie en verdere navigatie onder die mounts via bestaand `path_guard`-model.
|
||||
|
||||
Concreet aanbevolen model:
|
||||
- `/Volumes` wordt een speciale browse-entrypoint
|
||||
- listing van `/Volumes` bevat alleen de whitelisted mountnamen
|
||||
- `/Volumes/8TB/...` en `/Volumes/8TB_RAID1/...` worden daarna normaal browsebaar binnen de bestaande veiligheidsgrenzen
|
||||
|
||||
Waarom dit de beste v1-richting is:
|
||||
- sluit aan op de echte hoststructuur
|
||||
- behoudt securitycontrole centraal in backend
|
||||
- vermijdt frontend-hardcoding als primaire oplossing
|
||||
- is beperkt, uitlegbaar en testbaar
|
||||
|
||||
Niet aanbevolen voor v1:
|
||||
- puur frontend-aliasing
|
||||
- volledig openstellen van `/Volumes` als generieke root
|
||||
- tegelijk zowel aliasmodel als hostpathmodel als primaire UX blijven promoten zonder expliciete migratiekeuze
|
||||
Reference in New Issue
Block a user