Files
graph_explorer/issues/0010-table-node.md
T

72 lines
4.1 KiB
Markdown

---
id: 0010
title: Nodo tabla — contenedor cuadrado con filas que son nodos del grafo
status: pending
priority: medium
created: 2026-04-30
depends_on: [0004, 0005, 0008]
---
## Objetivo
Un tipo especial de nodo, **Table**, que se renderiza en el viewport como
un rectangulo (no circulo) y agrupa visualmente N entidades del grafo. Cada
fila de la tabla = un nodo real del grafo (con su `type_ref`, sus fields,
sus tags). Las filas se pueden **extraer** (salen al canvas como nodos
sueltos) y **meter** (un nodo suelto entra como fila).
Distinto del issue 0004 (vista tabla global por tipo): ese es una **ventana
auxiliar** que tabula entidades existentes; este es un **nodo en el grafo**
que existe en `entities` y posee filas via relaciones.
## Modelo de datos
- El nodo tabla es una entidad normal con `type_ref = 'Table'` y metadata:
```json
{
"row_type": "Person", // tipo esperado de las filas (puede ser vacio = mixto)
"columns": ["name","age","email"], // subset de fields del row_type a mostrar como columnas
"expanded": true // estado de UI persistido
}
```
- La pertenencia se modela con relaciones:
- `name = "CONTAINS_ROW"`, `from_entity = <table_id>`, `to_entity = <row_entity_id>`, `order = N`.
- Una fila puede pertenecer a varias tablas (varias relaciones `CONTAINS_ROW` apuntando al mismo nodo). Confirmado en la conversacion.
- Las columnas pueden ser fijas (`row_type` definido → columnas = subset de los `fields` de ese tipo) o libres (definidas por el creador de la tabla en `columns`).
## Render en viewport
- Forma: `square` o `rounded_square` con tamano dependiente del numero de filas (clamp a min/max).
- Cuando esta **colapsada**: caja con titulo + contador (`Table · 23 filas`).
- Cuando esta **expandida**: caja crece y dibuja un grid interno (filas x columnas) con los valores principales. Las filas son arrastrables individualmente.
- Las relaciones `CONTAINS_ROW` no se dibujan como aristas normales (serian ruido visual). En su lugar, una fila extraida muestra una arista fina punteada hacia su tabla de origen.
- Aristas entrantes/salientes del nodo tabla se dibujan al borde del rectangulo, no al centro.
## Operaciones
- **Crear tabla**: en context menu del viewport, "New table here". Pide `row_type` opcional. Crea entidad `Table` y la posiciona donde el click.
- **Anadir fila** (tabla expandida o seleccionada): boton "+ row" que crea una entidad nueva con `type_ref = row_type` (si esta definido) y la engancha via `CONTAINS_ROW`.
- **Extraer fila**: borra la relacion `CONTAINS_ROW`. La fila queda como nodo libre, posicionada al lado de la tabla.
- **Extraer multiples**: shift+click en filas dentro de la tabla expandida, "Extract selected".
- **Meter fila**: drag de un nodo sobre el rectangulo de una tabla. Confirm dialog si su `type_ref` no coincide con `row_type` de la tabla.
- **Editar fila**: doble-click en fila → abre Inspector con esa entidad seleccionada.
## Cambios en codigo
- `entity_ops`:
- `bool table_create(db_path, name, row_type, columns_csv, char* out_id)`.
- `bool table_add_row(db_path, table_id, char* out_row_id)` (crea entidad + relacion CONTAINS_ROW).
- `bool table_extract_row(db_path, table_id, row_id)` (borra solo la relacion).
- `bool table_attach_row(db_path, table_id, row_id, int order)`.
- `bool table_list_rows(db_path, table_id, vector<string>* out_row_ids)`.
- Renderer del viewport (`graph_viewport.cpp` y/o `graph_renderer`): branch para `is_table_node` (detectado por `type_ref == "Table"`) que dibuja rectangulo + grid expandido y devuelve hit-testing por filas individuales.
- `graph_load_from_operations`: filtrar las aristas `CONTAINS_ROW` para que no entren en el layout fisico (no aplican fuerzas).
## Definicion de hecho
- Crear tabla, anadir filas, extraer y meter filas funciona round-trip via SQLite.
- Tabla colapsada y expandida se renderizan correctamente en el viewport.
- Doble-click en fila enfoca el Inspector con esa entidad.
- Una fila puede pertenecer a varias tablas sin duplicarse.
- Borrar la tabla pregunta: "borrar tabla y todas sus filas" o "extraer filas y borrar solo la tabla".