Files
fn_registry/dev/data_table_integration_audit.md
T
egutierrez b9716a7cd6 chore: snapshot WIP previo + flow 0008 + 7 sub-issues (0112-0119)
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>
2026-05-18 18:17:08 +02:00

564 lines
25 KiB
Markdown

# data_table integration audit — 8 apps
Canonical pattern (from modules/data_table/data_table.md):
```cpp
static data_table::State g_table_state; // PERSISTENT entre frames
data_table::TableInput tbl;
tbl.name = "my_table";
tbl.headers = {"col1","col2"};
tbl.types = {data_table::ColumnType::String, data_table::ColumnType::Int};
tbl.cells = cells_ptr; // row-major flat array
tbl.rows = N;
tbl.cols = 2;
std::vector<data_table::TableEvent> events;
ImGui::BeginChild("##tbl_host");
data_table::render("##my_tbl_id", { tbl }, g_table_state, &events);
ImGui::EndChild();
for (const auto& ev : events) {
if (ev.kind == data_table::TableEventKind::RowDoubleClick) { ... }
}
```
Anti-patterns the audit flags:
- inline_begintable [warn]: app calls ImGui::BeginTable directly instead of data_table::render. Migrar la tabla a data_table::render con un TableInput.
- state_not_persistent [error]: data_table::State declarado dentro de funcion sin `static`. Mover a `static` local o miembro global; sino se pierde drill/sort/filtros cada frame.
- no_child_host [warn]: data_table::render se llama sin BeginChild/Begin en las ~30 lineas previas. Envolver con `ImGui::BeginChild("##host");``ImGui::EndChild();`.
- no_event_sink [info]: app declara uses_modules data_table_cpp pero no captura events_out. Pasar `&events` para reaccionar a double-click / right-click / ButtonClick.
- cmake_missing_link [error]: app.md declara `uses_modules: [data_table_cpp]` pero CMakeLists.txt no enlaza `fn_module_data_table`.
---
## app_gestion [warn] (apps/app_gestion)
### inline_begintable [warn] apps/app_gestion/main.cpp:722
snippet: if (ImGui::BeginTable("##linked_tbl", 4,
```
717 ? "?" : a->linked_build.c_str());
718 if (a->linked_modules.empty()) {
719 ImGui::TextDisabled("(sin info — la app no se ha buildeado todavia,"
720 " o no genera _modules_generated.cpp)");
721 } else {
>> 722 if (ImGui::BeginTable("##linked_tbl", 4,
723 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
724 ImGui::TableSetupColumn("module");
725 ImGui::TableSetupColumn("linked");
726 ImGui::TableSetupColumn("registry");
727 ImGui::TableSetupColumn("status");
```
## dag_engine_ui [warn] (apps/dag_engine_ui)
### inline_begintable [warn] apps/dag_engine_ui/tabs.cpp:382
snippet: if (ImGui::BeginTable("##dt_run_steps", 6, steps_flags)) {
```
377 ImGui::BeginChild("##run_steps_wrap", ImVec2(-1, ImGui::GetContentRegionAvail().y * 0.5f));
378 const ImGuiTableFlags steps_flags =
379 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
380 ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingStretchProp |
381 ImGuiTableFlags_ScrollY;
>> 382 if (ImGui::BeginTable("##dt_run_steps", 6, steps_flags)) {
383 ImGui::TableSetupScrollFreeze(0, 1);
384 ImGui::TableSetupColumn("Step", ImGuiTableColumnFlags_WidthStretch, 1.6f);
385 ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_WidthStretch, 2.2f);
386 ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 0.8f);
387 ImGui::TableSetupColumn("Exit", ImGuiTableColumnFlags_WidthStretch, 0.4f);
```
### inline_begintable [warn] apps/dag_engine_ui/tabs.cpp:731
snippet: if (ImGui::BeginTable("##health_kpis", 4,
```
726 "Trigger a DAG to populate health metrics.");
727 ImGui::End();
728 return;
729 }
730
>> 731 if (ImGui::BeginTable("##health_kpis", 4,
732 ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchSame))
733 {
734 ImGui::TableNextRow();
735
736 ImGui::TableNextColumn();
```
## data_factory [warn] (apps/data_factory)
### no_child_host [warn] apps/data_factory/tabs.cpp:291
snippet: data_table::render(dt_id, {tbl}, *st, &events);
```
286 }
287 cells_to_ptrs(*backing, *ptrs);
288 tbl.cells = ptrs->data();
289
290 std::vector<data_table::TableEvent> events;
>> 291 data_table::render(dt_id, {tbl}, *st, &events);
292
293 for (auto& ev : events) {
294 if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
295 ev.row >= 0 && ev.row < static_cast<int>(filtered.size()))
296 {
```
### no_child_host [warn] apps/data_factory/tabs.cpp:454
snippet: data_table::render("##dt_tables", {tbl}, g_st_tables, &tbl_events);
```
449 }
450 cells_to_ptrs(g_back_tables, g_ptrs_tables);
451 tbl.cells = g_ptrs_tables.data();
452
453 std::vector<data_table::TableEvent> tbl_events;
>> 454 data_table::render("##dt_tables", {tbl}, g_st_tables, &tbl_events);
455 for (auto& ev : tbl_events) {
456 if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
457 ev.row >= 0 && ev.row < static_cast<int>(tables.size()))
458 {
459 const auto& t = tables[ev.row];
```
### no_child_host [warn] apps/data_factory/tabs.cpp:531
snippet: data_table::render("##dt_databases", {tbl}, g_st_databases);
```
526 g_back_databases.push_back(d.last_seen_at.empty() ? "-" : d.last_seen_at);
527 }
528 cells_to_ptrs(g_back_databases, g_ptrs_databases);
529 tbl.cells = g_ptrs_databases.data();
530
>> 531 data_table::render("##dt_databases", {tbl}, g_st_databases);
532 }
533 ImGui::End();
534 }
535
536 // ---------------------------------------------------------------------------
```
### no_child_host [warn] apps/data_factory/tabs.cpp:619
snippet: data_table::render("##dt_kpis", {tbl}, g_st_kpis);
```
614 std::snprintf(buf, sizeof(buf), "%lld KB", kb_24h); g_back_kpis.push_back(buf);
615
616 cells_to_ptrs(g_back_kpis, g_ptrs_kpis);
617 tbl.cells = g_ptrs_kpis.data();
618
>> 619 data_table::render("##dt_kpis", {tbl}, g_st_kpis);
620 }
621
622 ImGui::Separator();
623 ImGui::TextDisabled("Computed client-side from %zu runs in cache.", runs_all.size());
624 ImGui::End();
```
### no_child_host [warn] apps/data_factory/tabs.cpp:883
snippet: data_table::render("##dt_node_runs", {tbl}, g_st_node_runs, &events);
```
878 }
879 cells_to_ptrs(g_back_node_runs, g_ptrs_node_runs);
880 tbl.cells = g_ptrs_node_runs.data();
881
882 std::vector<data_table::TableEvent> events;
>> 883 data_table::render("##dt_node_runs", {tbl}, g_st_node_runs, &events);
884
885 for (auto& ev : events) {
886 if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
887 ev.row >= 0 && ev.row < static_cast<int>(shown_runs.size()))
888 {
```
### no_child_host [warn] apps/data_factory/tabs.cpp:992
snippet: data_table::render("##dt_preview", {tbl}, g_st_preview, nullptr, true);
```
987 }
988 }
989 cells_to_ptrs(g_back_preview, g_ptrs_preview);
990 tbl.cells = g_ptrs_preview.data();
991
>> 992 data_table::render("##dt_preview", {tbl}, g_st_preview, nullptr, true);
993 }
994
995 // Pagination controls.
996 ImGui::Separator();
997 {
```
## graph_explorer [warn] (projects/osint_graph/apps/graph_explorer)
### inline_begintable [warn] projects/osint_graph/apps/graph_explorer/extract_panel.cpp:981
snippet: if (ImGui::BeginTable("##ents", 5,
```
976 }
977
978 // Tabla de entidades.
979 if (!res->entities.empty() &&
980 ImGui::CollapsingHeader("Entities", ImGuiTreeNodeFlags_DefaultOpen)) {
>> 981 if (ImGui::BeginTable("##ents", 5,
982 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
983 ImGuiTableFlags_ScrollY,
984 ImVec2(0.0f, 200.0f))) {
985 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 28.0f);
986 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 120.0f);
```
### inline_begintable [warn] projects/osint_graph/apps/graph_explorer/extract_panel.cpp:1027
snippet: if (ImGui::BeginTable("##rels", 5,
```
1022 }
1023
1024 // Tabla de relaciones.
1025 if (!res->relations.empty() &&
1026 ImGui::CollapsingHeader("Relations", ImGuiTreeNodeFlags_DefaultOpen)) {
>> 1027 if (ImGui::BeginTable("##rels", 5,
1028 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
1029 ImGuiTableFlags_ScrollY,
1030 ImVec2(0.0f, 160.0f))) {
1031 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 28.0f);
1032 ImGui::TableSetupColumn("From", ImGuiTableColumnFlags_WidthFixed, 100.0f);
```
### inline_begintable [warn] projects/osint_graph/apps/graph_explorer/main.cpp:1127
snippet: if (ImGui::BeginTable("##enr_params", 2,
```
1122 // con mas params de los que llenamos al abrir la ventana.
1123 if (g_app.enr_modal_param_bufs.size() < spec->params.size()) {
1124 g_app.enr_modal_param_bufs.resize(spec->params.size());
1125 }
1126
>> 1127 if (ImGui::BeginTable("##enr_params", 2,
1128 ImGuiTableFlags_SizingStretchProp |
1129 ImGuiTableFlags_NoBordersInBody)) {
1130 ImGui::TableSetupColumn("name", ImGuiTableColumnFlags_WidthFixed, 110.0f);
1131 ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch);
1132
```
### inline_begintable [warn] projects/osint_graph/apps/graph_explorer/views.cpp:885
snippet: if (ImGui::BeginTable("##insp_id", 2,
```
880 // Layout label-izquierda / input-derecha via 2-col table. El label
881 // alineado al frame del input y el input estirado al ancho restante.
882 ImGui::TextUnformatted("Identity");
883 ImGui::Separator();
884
>> 885 if (ImGui::BeginTable("##insp_id", 2,
886 ImGuiTableFlags_SizingStretchProp |
887 ImGuiTableFlags_NoBordersInBody)) {
888 ImGui::TableSetupColumn("k", ImGuiTableColumnFlags_WidthFixed, 90.0f);
889 ImGui::TableSetupColumn("v", ImGuiTableColumnFlags_WidthStretch);
890
```
### inline_begintable [warn] projects/osint_graph/apps/graph_explorer/views.cpp:958
snippet: if (ImGui::BeginTable("##insp_fields", 2,
```
953 ImGui::TextUnformatted("Fields");
954 ImGui::Separator();
955 const EntitySpec* spec = find_entity_spec(app.parsed_types,
956 app.insp_type_buf);
957
>> 958 if (ImGui::BeginTable("##insp_fields", 2,
959 ImGuiTableFlags_SizingStretchProp |
960 ImGuiTableFlags_NoBordersInBody)) {
961 ImGui::TableSetupColumn("k", ImGuiTableColumnFlags_WidthFixed, 90.0f);
962 ImGui::TableSetupColumn("v", ImGuiTableColumnFlags_WidthStretch);
963
```
### inline_begintable [warn] projects/osint_graph/apps/graph_explorer/views.cpp:1546
snippet: // OLD: ImGui::BeginTable("##tablev", 6, ...) with manual sort/filter/clipper.
```
1541 }
1542
1543 // ----------------------------------------------------------------------------
1544 // Table view (issue 0004) — migrated to data_table::render (issue 0081-J).
1545 //
>> 1546 // OLD: ImGui::BeginTable("##tablev", 6, ...) with manual sort/filter/clipper.
1547 // Per-column filter popups + chips toolbar + TabBar per type.
1548 // Click on row selected node in graph viewport.
1549 //
1550 // NEW: data_table::render() provides sort + filter + viz + stages.
1551 // AppState::table_dt_state persists the UI state between frames.
```
### inline_begintable [warn] projects/osint_graph/apps/graph_explorer/views.cpp:1854
snippet: if (col_count > 0 && ImGui::BeginTable("##te_rows", col_count, tflags,
```
1849 : (int)m.columns.size() + 2;
1850 ImGuiTableFlags tflags =
1851 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
1852 ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable |
1853 ImGuiTableFlags_SizingStretchProp;
>> 1854 if (col_count > 0 && ImGui::BeginTable("##te_rows", col_count, tflags,
1855 ImVec2(0, -ImGui::GetFrameHeightWithSpacing()))) {
1856 ImGui::TableSetupScrollFreeze(0, 1);
1857 if (is_group) {
1858 for (size_t i = 0; i < m.columns.size(); ++i) {
1859 bool is_id = (i == 0);
```
### inline_begintable [warn] projects/osint_graph/apps/graph_explorer/views.cpp:2292
snippet: if (ImGui::BeginTable("##te_fields", 5,
```
2287 // Fields table
2288 ImGui::Spacing();
2289 ImGui::TextUnformatted("Fields");
2290 ImGui::Separator();
2291
>> 2292 if (ImGui::BeginTable("##te_fields", 5,
2293 ImGuiTableFlags_BordersInnerV
2294 | ImGuiTableFlags_RowBg
2295 | ImGuiTableFlags_SizingStretchProp)) {
2296 ImGui::TableSetupColumn("name");
2297 ImGui::TableSetupColumn("type", ImGuiTableColumnFlags_WidthFixed, 90.0f);
```
### no_child_host [warn] projects/osint_graph/apps/graph_explorer/views.cpp:1632
snippet: data_table::render("##tablev_dt", {tbl}, app.table_dt_state);
```
1627 tbl.rows = s_rows_cached;
1628 tbl.cols = k_ncols;
1629
1630 // Render con chrome completo (barra de chips + breadcrumb).
1631 // app.table_dt_state persiste entre frames.
>> 1632 data_table::render("##tablev_dt", {tbl}, app.table_dt_state);
1633
1634 ImGui::End();
1635 }
1636
1637 // ----------------------------------------------------------------------------
```
## navegator_dashboard [warn] (projects/navegator/apps/navegator_dashboard)
### inline_begintable [warn] projects/navegator/apps/navegator_dashboard/autoextract_panel.cpp:528
snippet: if (ImGui::BeginTable("##ax_schema", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
```
523 {
524 std::lock_guard<std::mutex> lk(g_ax.mu);
525 sc_copy = g_ax.schema;
526 }
527
>> 528 if (ImGui::BeginTable("##ax_schema", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
529 ImGui::TableSetupColumn("field");
530 ImGui::TableSetupColumn("selector");
531 ImGui::TableSetupColumn("sample");
532 ImGui::TableSetupColumn("type");
533 ImGui::TableSetupColumn("keep");
```
### no_child_host [warn] projects/navegator/apps/navegator_dashboard/panels.cpp:234
snippet: data_table::render("##dt_browsers", {tbl}, g_browsers.dt_state, &dt_events, /*show_chrome=*/false);
```
229 data_table::BadgeRule{"visible", "#22c55e", "visible"},
230 };
231 }
232
233 std::vector<data_table::TableEvent> dt_events;
>> 234 data_table::render("##dt_browsers", {tbl}, g_browsers.dt_state, &dt_events, /*show_chrome=*/false);
235 for (auto& ev : dt_events) {
236 if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
237 ev.row >= 0 && ev.row < static_cast<int>(g_browsers.instances.size())) {
238 g_session().select_browser(g_browsers.instances[ev.row].port);
239 }
```
### no_child_host [warn] projects/navegator/apps/navegator_dashboard/panels.cpp:456
snippet: data_table::render("##dt_tabs", {tbl}, g_tabs_ui.dt_state, &dt_events, /*show_chrome=*/false);
```
451 data_table::BadgeRule{"no", "#6b7280", "no"},
452 };
453 }
454
455 std::vector<data_table::TableEvent> dt_events;
>> 456 data_table::render("##dt_tabs", {tbl}, g_tabs_ui.dt_state, &dt_events, /*show_chrome=*/false);
457 for (auto& ev : dt_events) {
458 if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
459 ev.row >= 0 && ev.row < static_cast<int>(visible_tabs.size())) {
460 const CdpTab* tp = visible_tabs[ev.row];
461 if (tp && !tp->ws_url.empty()) {
```
### no_child_host [warn] projects/navegator/apps/navegator_dashboard/panels.cpp:1016
snippet: data_table::render("##dt_wsframes", {ws_tbl}, g_dt_wsframes, false);
```
1011 data_table::BadgeRule{"ping", "#6b7280", "ping"},
1012 data_table::BadgeRule{"pong", "#6b7280", "pong"},
1013 };
1014 }
1015
>> 1016 data_table::render("##dt_wsframes", {ws_tbl}, g_dt_wsframes, false);
1017 ImGui::EndTabItem();
1018 }
1019 ImGui::EndTabBar();
1020 }
1021 }
```
### no_child_host [warn] projects/navegator/apps/navegator_dashboard/panels.cpp:1322
snippet: data_table::render("##dt_requests", {req_tbl}, g_net_ui.dt_state, &dt_events, /*show_chrome=*/true);
```
1317 cs.duration_warn_ms = 1000.0f;
1318 cs.duration_error_ms = 5000.0f;
1319 }
1320
1321 std::vector<data_table::TableEvent> dt_events;
>> 1322 data_table::render("##dt_requests", {req_tbl}, g_net_ui.dt_state, &dt_events, /*show_chrome=*/true);
1323 for (auto& ev : dt_events) {
1324 if (ev.kind == data_table::TableEventKind::RowDoubleClick &&
1325 ev.row >= 0 && ev.row < static_cast<int>(filtered.size())) {
1326 g_net_ui.selected_id = filtered[ev.row]->id;
1327 g_net_ui.selected_index = ev.row;
```
### inline_begintable [warn] projects/navegator/apps/navegator_dashboard/recipes_panel.cpp:238
snippet: } else if (ImGui::BeginTable("##recipes_tbl", 6,
```
233 }
234
235 if (rows_copy.empty()) {
236 ImGui::TextDisabled("No recipes in projects/navegator/profiles/default/recipes/.");
237 ImGui::TextDisabled("Use AutoExtract panel to create one.");
>> 238 } else if (ImGui::BeginTable("##recipes_tbl", 6,
239 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
240 ImGui::TableSetupColumn("name");
241 ImGui::TableSetupColumn("url_pattern");
242 ImGui::TableSetupColumn("last_status");
243 ImGui::TableSetupColumn("last_at");
```
## odr_console [ok] (projects/online_data_recopilation/apps/odr_console)
### no_event_sink [info] projects/online_data_recopilation/apps/odr_console:0
snippet: no TableEvent / events_out found in any source file
## registry_dashboard [warn] (projects/fn_monitoring/apps/registry_dashboard)
### inline_begintable [warn] projects/fn_monitoring/apps/registry_dashboard/views.cpp:380
snippet: if (ImGui::BeginTable("##kpi_grid", 4, flags)) {
```
375 // del registry). Si no hay datos cargados, queda vacio y el card mostrara
376 // solo valor + delta placeholder.
377 const float* spark_data = data.date_values.empty() ? nullptr : data.date_values.data();
378 const int spark_count = static_cast<int>(data.date_values.size());
379
>> 380 if (ImGui::BeginTable("##kpi_grid", 4, flags)) {
381 struct KPI { const char* label; float value; const char* fmt; const char* icon; };
382 const KPI cards[8] = {
383 {"Functions", static_cast<float>(stats.total_functions), "%.0f", TI_FUNCTION},
384 {"Types", static_cast<float>(stats.total_types), "%.0f", TI_HEXAGON},
385 {"Apps", static_cast<float>(stats.total_apps), "%.0f", TI_APPS},
```
### inline_begintable [warn] projects/fn_monitoring/apps/registry_dashboard/views.cpp:436
snippet: if (ImGui::BeginTable("##chart_grid", 4, flags)) {
```
431 void draw_charts(RegistryData& data, float height) {
432 const ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame
433 | ImGuiTableFlags_NoPadOuterX;
434 const float plot_h = height - 48.0f;
435
>> 436 if (ImGui::BeginTable("##chart_grid", 4, flags)) {
437 ImGui::TableNextRow();
438
439 ImGui::TableSetColumnIndex(0);
440 {
441 ImVec2 sz(ImGui::GetContentRegionAvail().x, height);
```
### inline_begintable [warn] projects/fn_monitoring/apps/registry_dashboard/views.cpp:648
snippet: if (ImGui::BeginTable("##monitor_kpi", 7, flags)) {
```
643
644 // 7 KPI cards: Calls / MCP / Reg% / Errors / Violations / Copies / Versions
645 // "MCP" = calls Claude lanza via tools registry-aware (mcp / fn_cli_run /
646 // heredoc). "Reg %" = porcentaje del total con function_id no vacio.
647 const ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_NoPadOuterX;
>> 648 if (ImGui::BeginTable("##monitor_kpi", 7, flags)) {
649 struct KPI { const char* label; float value; const char* icon; const char* fmt; };
650 const KPI cards[7] = {
651 {"Calls", static_cast<float>(cu.total_calls), TI_ACTIVITY, "%.0f"},
652 {"MCP", static_cast<float>(cu.total_mcp), TI_PLUG_CONNECTED, "%.0f"},
653 {"Reg %", static_cast<float>(cu.registry_pct), TI_PERCENTAGE, "%.1f%%"},
```
### inline_begintable [warn] projects/fn_monitoring/apps/registry_dashboard/views.cpp:1110
snippet: if (!ImGui::BeginTable("##proj_layout", 2, flags)) return;
```
1105 }
1106
1107 // Dos columnas: izquierda arbol, derecha detalle.
1108 const ImGuiTableFlags flags = ImGuiTableFlags_Resizable
1109 | ImGuiTableFlags_SizingStretchProp;
>> 1110 if (!ImGui::BeginTable("##proj_layout", 2, flags)) return;
1111
1112 ImGui::TableSetupColumn("tree", ImGuiTableColumnFlags_WidthStretch, 1.0f);
1113 ImGui::TableSetupColumn("detail", ImGuiTableColumnFlags_WidthStretch, 2.5f);
1114 ImGui::TableNextRow();
1115
```
### inline_begintable [warn] projects/fn_monitoring/apps/registry_dashboard/views.cpp:1448
snippet: if (!ImGui::BeginTable("##explorer_layout", 2, flags)) return;
```
1443 return;
1444 }
1445
1446 const ImGuiTableFlags flags = ImGuiTableFlags_Resizable
1447 | ImGuiTableFlags_SizingStretchProp;
>> 1448 if (!ImGui::BeginTable("##explorer_layout", 2, flags)) return;
1449
1450 ImGui::TableSetupColumn("list", ImGuiTableColumnFlags_WidthStretch, 1.0f);
1451 ImGui::TableSetupColumn("detail", ImGuiTableColumnFlags_WidthStretch, 2.4f);
1452 ImGui::TableNextRow();
1453
```
### inline_begintable [warn] projects/fn_monitoring/apps/registry_dashboard/work_tab.cpp:239
snippet: if (ImGui::BeginTable("##flows_work", 8,
```
234 // Flows table
235 ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::text_muted);
236 ImGui::TextUnformatted("Flows");
237 ImGui::PopStyleColor();
238
>> 239 if (ImGui::BeginTable("##flows_work", 8,
240 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
241 ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Resizable)) {
242 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 50.0f);
243 ImGui::TableSetupColumn("Name");
244 ImGui::TableSetupColumn("Pattern", ImGuiTableColumnFlags_WidthFixed, 110.0f);
```
### inline_begintable [warn] projects/fn_monitoring/apps/registry_dashboard/work_tab.cpp:272
snippet: if (ImGui::BeginTable("##top_issues_work", 7,
```
267 ImGui::Spacing();
268 ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::text_muted);
269 ImGui::TextUnformatted("Top issues (priority alta, not done)");
270 ImGui::PopStyleColor();
271
>> 272 if (ImGui::BeginTable("##top_issues_work", 7,
273 ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders |
274 ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Resizable)) {
275 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 70.0f);
276 ImGui::TableSetupColumn("Title");
277 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 80.0f);
```
### no_event_sink [info] projects/fn_monitoring/apps/registry_dashboard:0
snippet: no TableEvent / events_out found in any source file
## services_monitor [ok] (apps/services_monitor)
### no_event_sink [info] apps/services_monitor:0
snippet: no TableEvent / events_out found in any source file