Snapshot de WIP acumulado de sesiones previas antes de merge wave 1 del flow 0008 (kanban_cpp + agent_runner_api + DoD schema). Incluye: - dev/flows/0008-kanban-cpp-and-agent-workflows.md - dev/issues/0112-0119*.md (7 sub-issues) - WIP previo en cmd/fn/doctor.go, registry/*, modules/, cpp/, etc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 KiB
id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
| id | title | status | type | domain | scope | priority | depends | blocks | related | created | updated | tags | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0107g | Migrar inline ImGui::BeginTable a data_table::render en apps con tablas de datos reales | en-progreso | refactor |
|
multi-app | media |
|
|
2026-05-17 | 2026-05-17 |
|
0107g — Migrar inline BeginTable a data_table::render (data tables reales)
Parte del issue principal 0107. Detectado por audit_data_table_usage_go_infra (output en dev/data_table_integration_audit.md).
Problema
Audit automatico identifica ~12 hits de ImGui::BeginTable inline en apps que YA declaran uses_modules: [data_table_cpp]. Mezcla legitimos + bugs:
- Legitimos (NO migrar): KPI grids, schema forms k/v, layout 2-col splitters, chart grids. NO son tablas de datos.
- Bugs reales: tablas de datos con filas dinamicas + sort/filter potencial que reinventan logica que el modulo provee.
Resultado: codigo duplicado, comportamiento inconsistente, color/badge/sort/filter "casi-pero-no" igual entre apps. Conexiones raras: cada app personaliza su tabla a mano.
Decision
Migrar los hits identificados como bugs reales a data_table::render. Dejar los legitimos como excepciones documentadas en docs/MODULES_API.md::Cuando usar data_table::render vs BeginTable directo.
Tabla de migracion
| App | Path | Linea | Es bug? | Accion |
|---|---|---|---|---|
| dag_engine_ui | apps/dag_engine_ui/tabs.cpp | 382 | BUG (##dt_run_steps, 6 cols, scroll Y, runs dinamicas) |
Migrar |
| dag_engine_ui | apps/dag_engine_ui/tabs.cpp | 731 | LEGITIMO (##health_kpis, 4 cols stretch same, KPI grid) |
Dejar + comentar |
| navegator_dashboard | projects/navegator/apps/navegator_dashboard/autoextract_panel.cpp | 528 | BUG (##ax_schema, 5 cols, filas dinamicas schema) |
Migrar |
| navegator_dashboard | projects/navegator/apps/navegator_dashboard/recipes_panel.cpp | 238 | BUG (##recipes_tbl, 6 cols, filas dinamicas recipes) |
Migrar |
| graph_explorer | projects/osint_graph/apps/graph_explorer/extract_panel.cpp | 981 | BUG (##ents, 5 cols, filas dinamicas entities) |
Migrar |
| graph_explorer | projects/osint_graph/apps/graph_explorer/extract_panel.cpp | 1027 | BUG (##rels, 5 cols, filas dinamicas relations) |
Migrar |
| graph_explorer | projects/osint_graph/apps/graph_explorer/main.cpp | 1127 | LEGITIMO (##enr_params, form k/v) |
Dejar + comentar |
| graph_explorer | projects/osint_graph/apps/graph_explorer/views.cpp | 885 | LEGITIMO (##insp_id, inspector form k/v) |
Dejar + comentar |
| graph_explorer | projects/osint_graph/apps/graph_explorer/views.cpp | 958 | LEGITIMO (##insp_fields, inspector form) |
Dejar + comentar |
| graph_explorer | projects/osint_graph/apps/graph_explorer/views.cpp | 1546 | INFO comment, ya migrado a data_table::render | Ignorar (es comentario) |
| graph_explorer | projects/osint_graph/apps/graph_explorer/views.cpp | 1854 | BUG (##te_rows, col_count dinamico, data table type explorer) |
Migrar (segunda fase de la migration ya empezada) |
| graph_explorer | projects/osint_graph/apps/graph_explorer/views.cpp | 2292 | DISCUTIBLE (##te_fields, 5 cols, fields de un tipo — semi-dinamico) |
Evaluar; si rows >20 migrar, sino dejar |
| registry_dashboard | projects/fn_monitoring/apps/registry_dashboard/views.cpp | 380 | LEGITIMO (##kpi_grid, KPI cards) |
Dejar + comentar |
| registry_dashboard | projects/fn_monitoring/apps/registry_dashboard/views.cpp | 436 | LEGITIMO (##chart_grid, plots grid) |
Dejar + comentar |
| registry_dashboard | projects/fn_monitoring/apps/registry_dashboard/views.cpp | 648 | LEGITIMO (##monitor_kpi, KPI cards) |
Dejar + comentar |
| registry_dashboard | projects/fn_monitoring/apps/registry_dashboard/views.cpp | 1110 | LEGITIMO (##proj_layout, 2-col splitter) |
Dejar + comentar |
| registry_dashboard | projects/fn_monitoring/apps/registry_dashboard/views.cpp | 1448 | LEGITIMO (##explorer_layout, 2-col splitter) |
Dejar + comentar |
| registry_dashboard | projects/fn_monitoring/apps/registry_dashboard/work_tab.cpp | 239 | BUG (##flows_work, 8 cols, filas dinamicas flows) |
Migrar |
| registry_dashboard | projects/fn_monitoring/apps/registry_dashboard/work_tab.cpp | 272 | BUG (##top_issues_work, 7 cols, filas dinamicas issues) |
Migrar |
| app_gestion | apps/app_gestion/main.cpp | 722 | DISCUTIBLE (##linked_tbl, 4 cols, lista de modulos linked — semi-dinamico, rows <20) |
Evaluar; bias a dejar como esta |
Total a migrar (BUGs): 8 tablas en 4 apps. Total LEGITIMOS (dejar + comentar): 9. Total DISCUTIBLES: 2 — decision contextual. Total comentarios/already-migrated: 1.
Tareas
- 1.1 Migrar
dag_engine_ui/tabs.cpp:382(##dt_run_steps) →data_table::render. HECHO. Function col → Button action="open_fn"; Status → CategoricalChip; Duration → Duration renderer. - [~] 1.2 Migrar
navegator_dashboard/autoextract_panel.cpp:528(##ax_schema). ABORTADO: form editor con InputText/Checkbox editables inline en cada fila (field, selector, type, keep). data_table::render no soporta CellEdit como InputText inline. Comentado con LAYOUT-TABLE. - 1.3 Migrar
navegator_dashboard/recipes_panel.cpp:238(##recipes_tbl). HECHO. Patron B: 4 columnas Button (run/edit/delete/open_df) + ev.row para indexar yaml_path. last_status → CategoricalChip. - [~] 1.4 Migrar
graph_explorer/extract_panel.cpp:981(##ents). ABORTADO: form editor con InputText editables por fila (type_buf, name_buf) + Checkbox "sel". Mutacion directa de structs entities[i]. No mapeable a data_table. Comentado con LAYOUT-TABLE. - [~] 1.5 Migrar
graph_explorer/extract_panel.cpp:1027(##rels). ABORTADO: form editor con Checkbox "sel" + inmutabilidad necesaria (relations[i].selected se muta inline). Comentado con LAYOUT-TABLE. - [~] 1.6 Migrar
graph_explorer/views.cpp:1854(##te_rows). ABORTADO: interactividad app-específica no mapeable — Selectable + single-click ramificado por estado de promocion (promoted/unpromoted), dblclick promote-flow, PopupContextItem con promote/demote/focus condicionales, SmallButton Promote-out-of-group, paginacion manual. Equivalente exact en data_table events no existe. Comentado explicando razon. - 1.7 Migrar
registry_dashboard/work_tab.cpp:239(##flows_work). HECHO. 8 cols. Status + Risk → CategoricalChip. BeginChild host 220px. - 1.8 Migrar
registry_dashboard/work_tab.cpp:272(##top_issues_work). HECHO. 7 cols. Status + Deps + Prio → CategoricalChip. Deps string "-"/"OK"/"blocked" preserva logica de color original. BeginChild host -1. - 2.1 Anadir comentario
// LAYOUT-TABLE — KPI/form/splitter, no data; keep BeginTable inline.encima de los 9 hits LEGITIMOS para queaudit_data_table_usagelos excluya en proximas pasadas. HECHO en: ##health_kpis, ##enr_params, ##insp_id, ##insp_fields, ##kpi_grid, ##chart_grid, ##monitor_kpi, ##proj_layout, ##explorer_layout. Los 3 ABORTADOS tambien comentados con razon tecnica. - 2.2 Actualizar
audit_data_table_usage_go_infrapara leer ese comentario y filtrar[warn] -> [ignored:declared_layout_table]. - 3.1 Decidir los 2 DISCUTIBLES (
te_fields,linked_tbl) con criterio "si rows pueden crecer > 50, migrar". Decision: DEJAR.te_fieldsmax ~20 fields por tipo;linked_tblmax ~10 modules linked. Rows no escalan. - 4.1 Envolver TODAS las llamadas a
data_table::renderenImGui::BeginChildhost. HECHO en las 3 tablas migradas: flows_work (220px), top_issues_work (-1), recipes_tbl (300px), dt_run_steps (usa el BeginChild preexistente ##run_steps_wrap). - 5.1 Re-ejecutar audit:
Verificar: 0 BUG hits, 9 LEGITIMOS comentados, 11
./fn run audit_data_table_usageno_child_hostresueltos o documentados como excepcion. - 5.2 Build de las 4 apps modificadas. HECHO: dag_engine_ui, registry_dashboard, graph_explorer compilan OK (Linux). navegator_dashboard es Windows-only (CMakeLists.txt retorna en non-WIN32); sintaxis verificada via g++ -fsyntax-only sin errores.
Patrones de migracion canonicos
Patron A: ImGui::BeginTable inline → data_table::render basico
// ANTES
if (ImGui::BeginTable("##recipes_tbl", 6, flags)) {
ImGui::TableSetupColumn("name");
ImGui::TableSetupColumn("url_pattern");
// ...
for (const auto& r : recipes) {
ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TextUnformatted(r.name.c_str());
ImGui::TableNextColumn(); ImGui::TextUnformatted(r.url_pattern.c_str());
// ...
}
ImGui::EndTable();
}
// DESPUES
static data_table::State g_st_recipes;
static std::vector<std::string> g_back_recipes; // backing
static std::vector<const char*> g_ptrs_recipes; // ptrs row-major
g_back_recipes.clear();
for (const auto& r : recipes) {
g_back_recipes.push_back(r.name);
g_back_recipes.push_back(r.url_pattern);
// ... resto cols
}
g_ptrs_recipes.clear();
for (auto& s : g_back_recipes) g_ptrs_recipes.push_back(s.c_str());
data_table::TableInput tbl;
tbl.name = "recipes";
tbl.headers = {"name", "url_pattern", "last_status", "last_at", "tries", "ok"};
tbl.types = {data_table::ColumnType::String, data_table::ColumnType::String,
data_table::ColumnType::String, data_table::ColumnType::Date,
data_table::ColumnType::Int, data_table::ColumnType::Bool};
tbl.cells = g_ptrs_recipes.data();
tbl.rows = (int)recipes.size();
tbl.cols = 6;
// Status como CategoricalChip (ganancia inmediata sobre BeginTable)
tbl.column_specs.resize(tbl.cols);
for (int i = 0; i < tbl.cols; i++) tbl.column_specs[i].id = tbl.headers[i];
tbl.column_specs[2].renderer = data_table::CellRenderer::CategoricalChip;
tbl.column_specs[2].chips = {{"ok","#22c55e"},{"error","#ef4444"},{"pending","#a3a3a3"}};
std::vector<data_table::TableEvent> events;
ImGui::BeginChild("##recipes_host", ImVec2(-1, -1));
data_table::render("##recipes_dt", {tbl}, g_st_recipes, &events);
ImGui::EndChild();
for (const auto& ev : events) {
if (ev.kind == data_table::TableEventKind::RowDoubleClick) {
open_recipe_detail(ev.row);
}
}
Patron B: BeginTable inline con interactividad (boton por fila)
Si la BeginTable inline tiene un boton "Delete" / "Edit" por fila → migrar usando CellRenderer::Button + action_id:
// ANTES
ImGui::TableNextColumn();
if (ImGui::SmallButton(("Delete##" + r.id).c_str())) { delete_recipe(r.id); }
// DESPUES — anadir columna actions con button renderer
tbl.headers.push_back("actions");
tbl.types.push_back(data_table::ColumnType::String);
data_table::ColumnSpec actions_spec;
actions_spec.id = "actions";
actions_spec.renderer = data_table::CellRenderer::Button;
actions_spec.button_action = "delete_recipe";
actions_spec.button_label = "Delete";
actions_spec.button_color_hex = "#ef4444";
tbl.column_specs.push_back(actions_spec);
tbl.cols++;
// Backing extra
for (const auto& r : recipes) {
g_back_recipes.push_back(r.id); // celda actions = el id (consumido en ev.value)
}
// Handler
for (const auto& ev : events) {
if (ev.kind == data_table::TableEventKind::ButtonClick && ev.action_id == "delete_recipe") {
delete_recipe(ev.value); // ev.value == r.id de la fila clicada
}
}
Riesgos
- Backing storage: las apps deben mantener
std::vector<std::string>(estable) +std::vector<const char*>(ptrs row-major). Helpercells_to_ptrs()ya esta usado en data_factory — generalizar comocpp/functions/core/cells_to_ptrs.cppsi patron se repite >2 veces (ya pasa). - State persistente: cada migracion requiere
static data_table::State g_st_<name>;. Si la app tiene N tablas, N states. - Comportamiento sutil: filter/sort/freeze ahora son user-toggle, no controlados por la app. La app pierde control fino, pero gana consistencia.
Bonus: nueva funcion del registry cells_to_ptrs_cpp_core
Patron g_back + g_ptrs aparece en data_factory + (post 0107g) en 4 apps mas. Promover a funcion del registry:
// cpp/functions/core/cells_to_ptrs.h
namespace fn {
// Converts a row-major flat vector<string> to a row-major vector<const char*>
// pointing into the backing storage. Stable pointers — backing must not be
// resized while ptrs are in use.
void cells_to_ptrs(const std::vector<std::string>& back,
std::vector<const char*>& ptrs);
}
Issue separado o sub-task de 0107g segun apetito.
Notas
- El audit
audit_data_table_usage_go_infraya existe (FRESH 7d). Se referencia desdefn doctor modules(0107a) para mostrar drift en CI/dashboard.