diff --git a/CMakeLists.txt b/CMakeLists.txt index cdf549e..5c62b0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,11 @@ target_include_directories(odr_console PRIVATE target_link_libraries(odr_console PRIVATE SQLite::SQLite3) +# fn_table_viz: declarative table rendering stack (issue 0081-J). +if(TARGET fn_table_viz) + target_link_libraries(odr_console PRIVATE fn_table_viz) +endif() + if(WIN32) set_target_properties(odr_console PROPERTIES WIN32_EXECUTABLE TRUE) endif() diff --git a/app.md b/app.md index 5f45642..c5ef6f9 100644 --- a/app.md +++ b/app.md @@ -4,7 +4,12 @@ lang: cpp domain: tools description: "Lanzador GUI de funciones del registry para recolectar datos online. Panel de busqueda FTS5, jobs queue async (workers concurrentes), pipeline builder DAG, browser DuckDB, assertions/proposals. Aplica bucle reactivo de 5 pasos sobre operations.db propia." tags: [imgui, data-collection, scraping, duckdb, jobs, cdp] -uses_functions: [] +uses_functions: + - data_table_cpp_viz + - viz_render_cpp_viz + - compute_stage_cpp_core + - tql_to_sql_cpp_core + - llm_anthropic_cpp_core uses_types: [] framework: "imgui" entry_point: "main.cpp" diff --git a/main.cpp b/main.cpp index ee8018c..fcbbb8d 100644 --- a/main.cpp +++ b/main.cpp @@ -10,6 +10,7 @@ #include "core/icons_tabler.h" #include "core/tokens.h" #include "core/logger.h" +#include "viz/data_table.h" #include "data_registry.h" #include "data_collectors.h" @@ -40,6 +41,10 @@ static int g_coll_param_limit = 30; static std::string g_last_run_summary; // texto status del ultimo run static bool g_running = false; +// data_table::State persistentes (issue 0081-J: migration from inline BeginTable). +static data_table::State g_dt_collectors; +static data_table::State g_dt_results; + static void do_search() { g_results.clear(); g_selected = -1; @@ -111,29 +116,36 @@ static void draw_collectors() { return; } - if (ImGui::BeginTable("##collectors", 3, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_Resizable)) { - ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 180); - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 200); - ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableHeadersRow(); + // Build flat cells array for data_table::render (row-major, 3 cols). + { + static std::vector coll_cell_backing; + static std::vector coll_cells; - for (int i = 0; i < (int)g_collectors.size(); ++i) { - const auto& c = g_collectors[i]; - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - bool sel = (i == g_coll_selected); - if (ImGui::Selectable(c.id.c_str(), sel, - ImGuiSelectableFlags_SpanAllColumns)) { - g_coll_selected = i; - } - ImGui::TableSetColumnIndex(1); - ImGui::TextUnformatted(c.name.c_str()); - ImGui::TableSetColumnIndex(2); - ImGui::TextUnformatted(c.description.c_str()); + coll_cell_backing.clear(); + coll_cell_backing.reserve(g_collectors.size() * 3); + for (const auto& c : g_collectors) { + coll_cell_backing.push_back(c.id); + coll_cell_backing.push_back(c.name); + coll_cell_backing.push_back(c.description); } - ImGui::EndTable(); + coll_cells.resize(coll_cell_backing.size()); + for (size_t i = 0; i < coll_cell_backing.size(); ++i) + coll_cells[i] = coll_cell_backing[i].c_str(); + + data_table::TableInput tbl; + tbl.name = "collectors"; + tbl.headers = {"ID", "Name", "Description"}; + tbl.types = {data_table::ColumnType::String, + data_table::ColumnType::String, + data_table::ColumnType::String}; + tbl.cells = coll_cells.empty() ? nullptr : coll_cells.data(); + tbl.rows = (int)g_collectors.size(); + tbl.cols = 3; + // All columns use default Text renderer — no column_specs needed. + + ImGui::BeginChild("##collectors_dt", ImVec2(0, 200), false); + data_table::render("##dt_collectors", {tbl}, g_dt_collectors); + ImGui::EndChild(); } if (g_coll_selected >= 0 && @@ -192,32 +204,49 @@ static void draw_launcher() { ImGui::Separator(); - if (ImGui::BeginTable("##results", 4, - ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | - ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable)) { - ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn("Kind", ImGuiTableColumnFlags_WidthFixed, 80); - ImGui::TableSetupColumn("Domain", ImGuiTableColumnFlags_WidthFixed, 100); - ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableHeadersRow(); + // Build flat cells array for data_table::render (row-major, 4 cols). + { + static std::vector res_cell_backing; + static std::vector res_cells; - for (int i = 0; i < (int)g_results.size(); ++i) { - const auto& r = g_results[i]; - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); - bool sel = (i == g_selected); - if (ImGui::Selectable(r.id.c_str(), sel, - ImGuiSelectableFlags_SpanAllColumns)) { - g_selected = i; - } - ImGui::TableSetColumnIndex(1); - ImGui::TextUnformatted(r.kind.c_str()); - ImGui::TableSetColumnIndex(2); - ImGui::TextUnformatted(r.domain.c_str()); - ImGui::TableSetColumnIndex(3); - ImGui::TextUnformatted(r.description.c_str()); + res_cell_backing.clear(); + res_cell_backing.reserve(g_results.size() * 4); + for (const auto& r : g_results) { + res_cell_backing.push_back(r.id); + res_cell_backing.push_back(r.kind); + res_cell_backing.push_back(r.domain); + res_cell_backing.push_back(r.description); } - ImGui::EndTable(); + res_cells.resize(res_cell_backing.size()); + for (size_t i = 0; i < res_cell_backing.size(); ++i) + res_cells[i] = res_cell_backing[i].c_str(); + + // Column spec for Kind (col 1): Badge per kind value. + data_table::ColumnSpec cs_kind; + cs_kind.id = "kind"; + cs_kind.renderer = data_table::CellRenderer::Badge; + cs_kind.badges = { + data_table::BadgeRule{"function", "#3b82f6", ""}, + data_table::BadgeRule{"pipeline", "#8b5cf6", ""}, + data_table::BadgeRule{"component", "#f59e0b", ""}, + }; + + data_table::TableInput tbl; + tbl.name = "results"; + tbl.headers = {"ID", "Kind", "Domain", "Description"}; + tbl.types = {data_table::ColumnType::String, + data_table::ColumnType::String, + data_table::ColumnType::String, + data_table::ColumnType::String}; + tbl.cells = res_cells.empty() ? nullptr : res_cells.data(); + tbl.rows = (int)g_results.size(); + tbl.cols = 4; + tbl.column_specs.resize(4); // default Text for all + tbl.column_specs[1] = cs_kind; // Badge for Kind + + ImGui::BeginChild("##results_dt", ImVec2(0, -1), false); + data_table::render("##dt_results", {tbl}, g_dt_results); + ImGui::EndChild(); } if (g_selected >= 0 && g_selected < (int)g_results.size()) {