feat(nakui-ui): edit + delete de records (ciclo CRUD completo)
Cierra "no hay UI para editar/borrar" del commit anterior. Cada fila
de la lista gana dos botones (edit, delete); el form view se reusa
para alta y para edit; el delete es inline. Las mutaciones pasan por
LogEntry::Morphism con sus ops, asi el replay restaura el estado
correcto.
Cambios:
- MetaUi.editing: Option<(String, Uuid)> nuevo. Set al click ✎,
cleared al cambiar de view o tras submit.
- open_edit(mod_idx, entity, id, cx): setea editing, busca primer
Form view del modulo cuya entity matchee, navega ahi.
- select_view extendido: cuando carga un Form, si editing matchea y
el record existe, pre-llena cada input con value_to_input_text del
record (inverso de parse_field_value).
- commit_seed ramifica:
- Edit path: emite LogEntry::Morphism { name: "ui.edit_record",
ops: [Set per field] }. Aplica via store.apply.
- Seed path: alta nueva (comportamiento previo).
- commit_delete(entity, id): emite LogEntry::Morphism { name:
"ui.delete_record", ops: [Delete] } + apply.
- Render del form: titulo y submit label cambian segun editing
("Editar customer abc..." / "Guardar cambios").
- Render de la lista: dos columnas nuevas — id, acciones. Cada fila
con ✎ (edit, accent) y ✕ (delete, rojo) + hover states.
Coherencia con el modelo: todo cambio post-seed pasa por ops dentro
de Morphism. nakui-explorer muestra estos morphisms con sus ops en
la timeline.
Trade-offs:
- schema_hash: None sigue (legacy path) hasta Action::Morphism
wireé Manifest.
- Delete sin confirmacion (1 click).
- Edit sobreescribe todos los campos del form (no delta-only).
Tests: 3 nuevos. 10 totales:
- value_to_input_text_inverse_of_parse + round_trip — la propiedad
del pre-llenado.
- event_log_replay_handles_full_crud_cycle — E2E: seed + edit +
delete via log, replay desde cero deja store vacio. Replay parcial
deja valores editados.
Activacion:
NAKUI_EVENT_LOG=~/.nakui/state.jsonl \\
NAKUI_MODULES_DIR=examples/nakui-modules \\
cargo run -p nakui-ui
This commit is contained in:
@@ -6,6 +6,86 @@ ratio/diff ver `git show <sha>`.
|
||||
|
||||
## 2026-05-09
|
||||
|
||||
### feat(nakui-ui): edit + delete de records (ciclo CRUD completo)
|
||||
Cierra "no hay UI para editar/borrar records existentes" del commit
|
||||
anterior. Cada fila de la lista gana dos botones (✎ edit, ✕ delete);
|
||||
el form view se reusa para alta y para edit; el delete es inline.
|
||||
Las mutaciones pasan por `LogEntry::Morphism` con sus ops, así el
|
||||
replay restaura el estado correcto.
|
||||
|
||||
Cambios:
|
||||
|
||||
- **`MetaUi.editing: Option<(String, Uuid)>`** nuevo. Set al click
|
||||
en ✎; cleared al cambiar de view o tras submit exitoso.
|
||||
- **`open_edit(mod_idx, entity, id, cx)`**: setea `editing`, busca la
|
||||
primera Form view del módulo cuya `entity` matchee, navega ahí. Si
|
||||
el módulo no tiene Form para esa entity → toast con error
|
||||
("no hay form view para entity X").
|
||||
- **`select_view`** extendido: cuando carga un Form, si `editing`
|
||||
matchea esa entity y el record existe en el store, pre-llena cada
|
||||
input con el valor del record (vía nuevo helper
|
||||
`value_to_input_text` — inverso de `parse_field_value`).
|
||||
- **`commit_seed`** ramifica:
|
||||
- **Edit path** (cuando `editing.is_some()` y entity matchea):
|
||||
emite `LogEntry::Morphism { name: "ui.edit_record", ops:
|
||||
[Set { path, value } for each field], params: { entity, id,
|
||||
fields } }`. Aplica al store via `apply(&ops)`.
|
||||
- **Seed path** (alta nueva): comportamiento previo.
|
||||
- **`commit_delete(entity, id)`**: emite `LogEntry::Morphism {
|
||||
name: "ui.delete_record", ops: [Delete { entity, id }] }` + apply.
|
||||
- **Render del form**: título cambia a "Editar customer abc12345"
|
||||
cuando `editing` matchea; submit label cambia a "Guardar cambios
|
||||
en customer".
|
||||
- **Render de la lista**: dos columnas nuevas — "id" y "acciones".
|
||||
Cada fila tiene ✎ (accent color, click → open_edit) y ✕ (rojo,
|
||||
click → commit_delete). Hover states.
|
||||
|
||||
Ramificación visible en el event log:
|
||||
```
|
||||
{"kind":"seed","seq":0,"entity":"customer","id":"abc...","data":{"name":"Acme"}}
|
||||
{"kind":"morphism","seq":1,"morphism":"ui.edit_record","ops":[
|
||||
{"op":"set","path":{"entity":"customer","id":"abc...","field":"name"},
|
||||
"value":"Acme S.A."}
|
||||
]}
|
||||
{"kind":"morphism","seq":2,"morphism":"ui.delete_record","ops":[
|
||||
{"op":"delete","entity":"customer","id":"abc..."}
|
||||
]}
|
||||
```
|
||||
Coherente con el modelo de Nakui — todo cambio post-seed pasa por
|
||||
ops dentro de Morphism. `nakui-explorer` muestra estos morphisms
|
||||
con sus ops claros en su timeline.
|
||||
|
||||
Trade-offs documentados:
|
||||
- **`schema_hash: None`** sigue para los morphism de la UI (legacy/
|
||||
pre-versioning path) hasta que `Action::Morphism` cargue Manifest
|
||||
schemas.
|
||||
- **Delete sin confirmación**: 1 click, sin modal. Para MVP es OK
|
||||
(los records son recuperables vía replay parcial), pero un futuro
|
||||
iter agregaría confirmación.
|
||||
- **Edit sobreescribe TODOS los campos del form**, no sólo los
|
||||
cambiados — emite N ops Set, una por field. Adecuado para forms
|
||||
chicos; para forms con muchos campos optimizar a delta-only.
|
||||
|
||||
Tests: 3 nuevos (10 totales en nakui-ui):
|
||||
- `value_to_input_text_inverse_of_parse` y
|
||||
`value_to_input_then_parse_round_trip` — la propiedad fundamental
|
||||
del pre-llenado: text → parse devuelve el Value original.
|
||||
- `event_log_replay_handles_full_crud_cycle` — E2E del log: escribe
|
||||
Seed + Morphism(Set ops) + Morphism(Delete op), replay desde cero,
|
||||
verifica que el store termina vacío (delete fue el último). Verifica
|
||||
además que un replay parcial (sin el delete) deja los valores
|
||||
editados.
|
||||
|
||||
Activación:
|
||||
```sh
|
||||
NAKUI_EVENT_LOG=~/.nakui/state.jsonl \
|
||||
NAKUI_MODULES_DIR=examples/nakui-modules \
|
||||
cargo run -p nakui-ui
|
||||
# Crear un customer, click ✎ en su fila, modificar campos,
|
||||
# "Guardar cambios". Click ✕ en otra fila para borrar.
|
||||
# Cerrar y reabrir: el state persiste con todos los cambios.
|
||||
```
|
||||
|
||||
### feat(nakui-ui): persistencia con event log + replay al startup
|
||||
Cierra "sin persistencia entre runs" del commit anterior. Cada
|
||||
`SeedEntity` se appendea al `nakui_core::event_log::EventLog` con
|
||||
|
||||
Reference in New Issue
Block a user