--- id: 0011 title: Nodo tabla — UI expandida, promote/demote, ingesta CSV/Parquet status: completed priority: high created: 2026-05-01 completed: 2026-05-01 depends_on: [0010] --- ## Objetivo Fase 2 del nodo tabla. Sobre el cimiento DuckDB de 0010, anade UI completa: expandir nodo Table en el viewport para ver paginas de filas, promover una fila a entidad del grafo (nodo libre + arista punteada hacia su Table) y demover de vuelta. Ingesta de CSV / Parquet como punto de entrada para materializar tablas grandes. ## UI expandida - Click sobre nodo Table -> selecciona; doble click -> toggle `expanded` en metadata. - Cuando expanded: - El cuadrado overlay crece para acomodar grid de cabecera + ~20 filas visibles. Mas filas exigen scroll dentro del overlay. - Cabecera con nombres de `columns[]`. Anchura proporcional al texto, max cap a un % del overlay. - Filas paginadas via `ImGuiListClipper` + `tableview_page(offset,limit)`. - Indicador "promovida" (chip o color) en filas que ya estan en `entities`. - Doble-click en fila -> abre Inspector con esa entidad si esta promovida; si no, la promueve y abre Inspector. - Aristas entrantes/salientes del nodo Table se siguen dibujando al centro (mejora a "al borde" se aplaza). ## Promote / demote - Context menu sobre fila visible (overlay expandido): - "Promote to graph node": crea entidad en `operations.db` con metadata de origen, posiciona el nodo al lado del Table y dibuja arista punteada hacia el Table (overlay). - "Demote": deletea la entidad. La fila sigue viva en DuckDB. - Una fila puede estar promovida una sola vez por (duckdb_path, table, row_id) — el helper de promocion debe checar y hacer no-op idempotente. ## Ingesta - Boton/comando "Import dataset..." en menu o context menu del canvas. - Modal con: - Path al CSV / Parquet / JSON. - Nombre de la tabla DuckDB destino. - row_type (combo con los entity types del proyecto + "(none)"). - Boton "Import" -> ejecuta: ```sql CREATE TABLE AS SELECT * FROM read_csv_auto(''); ``` sobre `tables/.duckdb` (crea el .duckdb si no existe). - Tras import, crea automaticamente un nodo Table en el viewport apuntando a la nueva tabla. ## Cambios en codigo - `tableview.{h,cpp}`: - `tableview_promote_row(ops_db, duckdb_path, duck_table, row_id, row_type, out_entity_id)`. - `tableview_demote_row(ops_db, entity_id)`. - `tableview_ingest_file(duckdb_path, file_path, dest_table, *file_kind)`. - `views.cpp`: - Render expandida via overlay. Hit-testing por fila (rect intersection). - Modal "Import dataset...". - `main.cpp`: - Wire context menu items. Recargar grafo tras promote/demote/ingest. ## Definicion de hecho - Toggle expanded persiste en `entities.metadata` (JSON write). - Tabla con 1M filas se navega con scroll fluido (paginacion 200 filas). - Promote: la entidad creada aparece como nodo libre adyacente al Table, unida por arista punteada (visual solamente — no es relacion en BD). - Demote: el nodo desaparece, la fila sigue contandose en `tableview_count`. - Ingesta de CSV de 100k filas tarda < 5 s y deja la tabla lista para mostrar. - Doble-click en fila no promovida la promueve y enfoca Inspector.