242 lines
5.5 KiB
Markdown
242 lines
5.5 KiB
Markdown
# UI_EDIT_V1_DESIGN.md
|
|
|
|
## 1. Scope
|
|
|
|
`Edit v1` is een eenvoudige teksteditor in de webui, gekoppeld aan de functiebalkactie `Edit`.
|
|
|
|
In scope:
|
|
- alleen tekstbestanden
|
|
- alleen files, geen directories
|
|
- openen, wijzigen en opslaan van tekstinhoud
|
|
- eenvoudige modal-editor
|
|
|
|
Out of scope:
|
|
- geen binary files
|
|
- geen PDF
|
|
- geen rich text
|
|
- geen collaborative editing
|
|
- geen autosave
|
|
|
|
---
|
|
|
|
## 2. Ondersteunde bestandstypen in v1
|
|
|
|
Voorstel v1:
|
|
|
|
- `txt`: ja
|
|
- `log`: ja
|
|
- `md`: ja
|
|
- `yml` / `yaml`: ja
|
|
- `json`: ja
|
|
- `js`: ja
|
|
- `css`: ja
|
|
- `html`: ja
|
|
- `Dockerfile`: ja
|
|
- `Containerfile`: ja
|
|
|
|
De allowlist blijft gelijk aan `View v1`, zodat `View` en `Edit` inhoudelijk consistent zijn.
|
|
|
|
---
|
|
|
|
## 3. UI/UX
|
|
|
|
### Openen
|
|
- `Edit` opent via de functiebalk
|
|
- alleen geldig bij exact 1 geselecteerde file
|
|
- alleen bij ondersteund teksttype
|
|
|
|
### Modal
|
|
- openen in modal boven de bestaande dual-pane UI
|
|
- modal bevat:
|
|
- titel/header
|
|
- bestandsnaam
|
|
- volledig pad
|
|
- bewerkbaar tekstgebied
|
|
- `Save`
|
|
- `Cancel`
|
|
- rechtsboven `X`
|
|
|
|
### Sluiten
|
|
- `Cancel` sluit zonder opslaan
|
|
- `X` sluit zonder opslaan
|
|
- `Escape`:
|
|
- als geen onopgeslagen wijzigingen: direct sluiten
|
|
- als wel onopgeslagen wijzigingen: waarschuwing/bevestiging tonen
|
|
|
|
### Inhoud
|
|
- scrollbaar tekstgebied
|
|
- monospace presentatie
|
|
- selecteerbaar en bewerkbaar
|
|
- geen syntax highlighting als dat extra dependencies vraagt
|
|
|
|
### Dirty state
|
|
- modal houdt een eenvoudige `isDirty` status bij
|
|
- verschil tussen originele inhoud en huidige inhoud bepaalt of waarschuwing nodig is
|
|
|
|
---
|
|
|
|
## 4. Backend
|
|
|
|
### Nieuwe endpoint(s)
|
|
|
|
Voorstel:
|
|
- hergebruik `GET /api/files/view?path=...` voor initial read
|
|
- nieuw write-endpoint:
|
|
- `POST /api/files/save`
|
|
|
|
Voorstel request shape:
|
|
- `path`
|
|
- `content`
|
|
- `expected_modified` of vergelijkbare timestamp/hash alleen als conflictcheck in v1 wordt gekozen
|
|
|
|
Voorstel response shape:
|
|
- `path`
|
|
- `size`
|
|
- `modified`
|
|
|
|
### Relatie met bestaand view-model
|
|
|
|
`Edit` gebruikt dezelfde type-allowlist en dezelfde padvalidatie als `View`.
|
|
|
|
Pragmatische lijn:
|
|
- `View` blijft read-only preview
|
|
- `Edit` leest initieel via `View` of een gedeelde servicefunctie
|
|
- `Save` schrijft alleen naar hetzelfde pad binnen whitelist
|
|
|
|
### Validatie
|
|
|
|
- alle paden via bestaand `path_guard`
|
|
- directories afwijzen
|
|
- unsupported types afwijzen
|
|
- write alleen binnen whitelisted roots
|
|
|
|
### Grote bestanden
|
|
|
|
Voorstel:
|
|
- dezelfde leeslimiet als `View` is **niet** voldoende voor edit
|
|
- `Edit v1` moet alleen openen tot een veilige editorlimiet, bijvoorbeeld `256 KiB` of `512 KiB`
|
|
- boven die limiet:
|
|
- openen blokkeren met duidelijke foutmelding
|
|
- geen partial edit voor grote bestanden in v1
|
|
|
|
Reden:
|
|
- partial content bewerken zonder volledige file-context is onveilig en verwarrend
|
|
|
|
---
|
|
|
|
## 5. Veiligheid en conflictgedrag
|
|
|
|
### Wijziging intussen op schijf
|
|
|
|
Voorstel v1:
|
|
- **wel** eenvoudige optimistic locking / modified timestamp check
|
|
|
|
Mechaniek:
|
|
- read-response bevat `modified`
|
|
- save-request stuurt `expected_modified`
|
|
- backend vergelijkt actuele `mtime`
|
|
- mismatch geeft conflictfout
|
|
|
|
Voordeel:
|
|
- beperkt risico op stil overschrijven
|
|
- technisch klein genoeg voor v1
|
|
|
|
### Readonly/permissieproblemen
|
|
|
|
Bij save:
|
|
- permissieprobleem of readonly file -> `io_error` of specifieker `permission_denied` als we die foutcode toevoegen
|
|
|
|
Voorstel:
|
|
- als bestaande foutset compact moet blijven, map dit in v1 naar `io_error` met duidelijke boodschap
|
|
|
|
### Foutmodel
|
|
|
|
Minimaal:
|
|
- `path_not_found`
|
|
- `path_traversal_detected`
|
|
- `invalid_root_alias`
|
|
- `type_conflict`
|
|
- `unsupported_type`
|
|
- `conflict`
|
|
- `io_error`
|
|
|
|
`conflict` wordt gebruikt voor modified-timestamp mismatch.
|
|
|
|
---
|
|
|
|
## 6. Scopebeperking
|
|
|
|
Niet in v1:
|
|
- geen syntax highlighting als dat extra dependencies vraagt
|
|
- geen undo/redo systeem buiten browser-native textarea gedrag
|
|
- geen find/replace
|
|
- geen multi-file edit
|
|
- geen directory edit
|
|
- geen split view diff
|
|
|
|
---
|
|
|
|
## 7. Impactanalyse
|
|
|
|
Waarschijnlijk te wijzigen backendbestanden:
|
|
- `webui/backend/app/api/routes_files.py`
|
|
- `webui/backend/app/api/schemas.py`
|
|
- `webui/backend/app/services/file_ops_service.py`
|
|
- `webui/backend/app/fs/filesystem_adapter.py`
|
|
- nieuwe golden tests voor save/edit flow
|
|
|
|
Waarschijnlijk te wijzigen frontendbestanden:
|
|
- `webui/html/index.html`
|
|
- `webui/html/app.js`
|
|
- `webui/html/style.css`
|
|
- `webui/backend/tests/golden/test_ui_smoke_golden.py`
|
|
|
|
### Regressierisico
|
|
|
|
- `Edit` enabled/disabled toestand kan verkeerd meelopen met huidige selectie
|
|
- modal-keyboardgedrag kan botsen met paneelnavigatie
|
|
- save-conflict of dirty-state kan leiden tot onduidelijk UX-gedrag
|
|
- onveilige overschrijving zonder conflictcheck moet vermeden worden
|
|
|
|
Mitigatie:
|
|
- dezelfde selectievoorwaarden als `View`
|
|
- keyboard shortcuts blokkeren zolang editor open is
|
|
- expliciete dirty-state en save-conflict handling
|
|
|
|
---
|
|
|
|
## 8. Teststrategie
|
|
|
|
### Golden tests
|
|
|
|
Voor backend:
|
|
- edit/open success voor ondersteund tekstbestand
|
|
- save success
|
|
- unsupported type
|
|
- directory -> type conflict
|
|
- path not found
|
|
- traversal attempt
|
|
- conflict bij gewijzigde file
|
|
- io_error bij write failure
|
|
|
|
### UI smoke/regressietests
|
|
|
|
Aanpassen:
|
|
- `Edit` knop aanwezig in functiebalk
|
|
- edit-modal container aanwezig in HTML
|
|
- save/cancel controls aanwezig
|
|
|
|
### Handmatige validatie
|
|
|
|
- `Edit` enabled bij exact 1 ondersteunde file
|
|
- `Edit` disabled bij:
|
|
- geen selectie
|
|
- meerdere selectie
|
|
- directoryselectie
|
|
- unsupported filetype
|
|
- modal opent met juiste inhoud
|
|
- `Save` schrijft wijziging correct weg
|
|
- `Cancel` sluit zonder opslaan
|
|
- `Escape` sluit alleen veilig volgens dirty-state regel
|
|
- conflictmelding bij tussentijdse externe wijziging
|