feat(nakui-ui): FieldKind::EntityRef — selector clickable de records existentes

Cierra el principal trade-off documentado del commit anterior:
"Inputs UUID a mano (no dropdown)". Los formularios pueden declarar
un campo entity_ref que apunta a una entity y el runtime renderea
una lista clickable de records existentes; click selecciona, el UUID
queda guardado para el submit.

Schema:
- Nueva variante FieldKind::EntityRef (serializa como "entity_ref").
- FieldSpec.ref_entity: Option<String> nuevo. validate() chequea que
  cualquier field con kind=entity_ref tenga ref_entity set.
- Nuevo SchemaError::EntityRefMissingTarget.

Runtime:
- render_entity_ref_selector helper: lista clickable debajo del input,
  cada item con etiqueta humana (heuristica: name > label > title >
  sku > sku_id > UUID corto) y click handler via cx.listener que
  setea el TextInput con el UUID completo. Highlight en accent color
  para el seleccionado.
- parse_field_value(EntityRef) devuelve string raw — validacion como
  Uuid es responsabilidad de commit_morphism downstream.
- Mensaje "(sin {entity}: crea uno antes...)" cuando lista vacia —
  el user sabe que hacer.

Demo actualizado sales_engine: vender_form.stock_id_input y
caja_id_input cambian a kind=entity_ref. Flujo nuevo: click en Stock
listado bajo input, click en Caja, escribir venta_id/cantidad/precio/
timestamp, submit. Sin copiar UUIDs.

Tests: 2 nuevos schema (validate detecta EntityRef sin ref_entity y
acepta con ref_entity) + 4 nuevos runtime (parse, human_label cubre
todos los key fallbacks). 29 tests totales (16 + 8 + 5).

Pendientes: confirmacion de delete, snapshot/compaction del log,
edit delta-only, validacion estricta de params del morphism via
FieldKind del FieldSpec en lugar de infer_param_value.
This commit is contained in:
Sergio
2026-05-09 20:48:59 +00:00
parent 932e7464d7
commit fc72726666
4 changed files with 321 additions and 4 deletions
+63
View File
@@ -6,6 +6,69 @@ ratio/diff ver `git show <sha>`.
## 2026-05-09
### feat(nakui-ui): FieldKind::EntityRef — selector clickable de records existentes
Cierra el principal trade-off documentado del commit anterior:
"Inputs UUID a mano (no dropdown)". Los formularios pueden declarar
un campo `entity_ref` que apunta a una entity y el runtime renderea
una lista clickable de records existentes; click selecciona, el
UUID queda guardado para el submit.
Schema `nakui-ui-schema`:
- **Nueva variante `FieldKind::EntityRef`** (serializa como
`"entity_ref"` en JSON).
- **`FieldSpec.ref_entity: Option<String>`** nuevo. Indica qué
entity ofrecer en el selector. `validate()` chequea que cualquier
field con `kind=entity_ref` tenga `ref_entity` set.
- Nuevo error tipado `SchemaError::EntityRefMissingTarget`.
Runtime `nakui-ui`:
- **`render_entity_ref_selector(field_name, target_entity, ...)`** —
helper que arma la lista debajo del input. Cada item:
- Etiqueta humana via `human_label_for_record` (heurística:
`name``label``title``sku``sku_id` → fallback al
UUID corto).
- Click handler vía `cx.listener` que llama
`input.set_text(uuid_completo)` — el TextInput interno queda
como source-of-truth, así que `commit_seed` y `commit_morphism`
leen el UUID seleccionado sin saber que vino de un selector.
- Highlight en accent color cuando el item es el actualmente
seleccionado (compara contra el contenido del TextInput).
- **`parse_field_value(EntityRef, raw)`** devuelve string del raw
(la validación como Uuid ocurre downstream en `commit_morphism`).
- Mensaje "(sin {entity}: creá uno antes para referenciar)" cuando
la lista está vacía — el user sabe qué hacer en lugar de quedarse
trabado.
Demo actualizado: `examples/nakui-modules/sales_engine/module.json`:
- `vender_form.fields.stock_id_input` y `caja_id_input` cambian de
`kind: "text"` a `kind: "entity_ref"` con `ref_entity: "Stock"`
y `"Caja"` respectivamente.
- Ahora el flujo "Vender" es: (1) click en una Stock listada bajo
el input, (2) click en una Caja, (3) escribir venta_id/cantidad/
precio_unitario/timestamp, (4) submit. Sin copiar UUIDs.
Tests:
- 2 nuevos en schema: `validate_catches_entity_ref_without_target`
y `entity_ref_with_target_validates_clean`. 8 totales.
- 4 nuevos en runtime: `parse_field_entity_ref_returns_string`,
`human_label_for_record_prefers_name_over_id`,
`human_label_falls_back_through_label_title_sku`,
`human_label_falls_back_to_id_when_no_known_keys`. 16 totales.
- Integration de los 7 demos sigue verde — el demo `sales_engine`
ahora valida con EntityRef + ref_entity correctamente set.
29 tests totales nakui-ui + schema, 100% verde. El demo
`sales_engine` carga limpio con la nueva forma del schema.
Pendientes futuros:
- **Confirmación de delete** — modal antes de borrar.
- **Snapshot/compaction** del log para repos grandes.
- **Edit delta-only** (sólo campos modificados).
- **Validación de tipos en params del morphism**: `FieldKind`
declarado en el FieldSpec se podría usar para forzar parseo
estricto en `commit_morphism` en lugar de la heurística
`infer_param_value`.
### feat(nakui-ui): Action::Morphism wired al pipeline real (compute → log → apply)
Cierra el último gran TODO de la metainterfaz Nakui: las acciones
`Action::Morphism` ya no son un toast informativo; despachan al