#include "views.h" #include "imgui.h" #include "implot.h" #include "viz/kpi_card.h" #include "viz/bar_chart.h" #include "viz/pie_chart.h" #include "viz/table_view.h" #include "viz/sparkline.h" #include "core/dashboard_panel.h" #include "core/dashboard_grid.h" #include "core/fps_overlay.h" #include "core/fullscreen_window.h" #include static std::vector to_cstr(const std::vector& v) { std::vector out; out.reserve(v.size()); for (auto& s : v) out.push_back(s.c_str()); return out; } void draw_kpi_row(const RegistryStats& stats) { float tested_pct = stats.total_functions > 0 ? 100.0f * stats.tested_functions / stats.total_functions : 0.0f; float pure_pct = stats.total_functions > 0 ? 100.0f * stats.pure_functions / stats.total_functions : 0.0f; dashboard_grid_begin(8, 8.0f); kpi_card("Functions", static_cast(stats.total_functions), 0, nullptr, 0, "%.0f"); dashboard_grid_next(); kpi_card("Types", static_cast(stats.total_types), 0, nullptr, 0, "%.0f"); dashboard_grid_next(); kpi_card("Apps", static_cast(stats.total_apps), 0, nullptr, 0, "%.0f"); dashboard_grid_next(); kpi_card("Analysis", static_cast(stats.total_analysis), 0, nullptr, 0, "%.0f"); dashboard_grid_next(); kpi_card("Unit Tests", static_cast(stats.total_unit_tests), 0, nullptr, 0, "%.0f"); dashboard_grid_next(); kpi_card("Proposals", static_cast(stats.total_proposals), 0, nullptr, 0, "%.0f"); dashboard_grid_next(); kpi_card("Tested", tested_pct, 0, nullptr, 0, "%.0f%%"); dashboard_grid_next(); kpi_card("Pure", pure_pct, 0, nullptr, 0, "%.0f%%"); dashboard_grid_end(); } void draw_charts(RegistryData& data, float height) { dashboard_grid_begin(4, 8.0f); if (dashboard_panel_begin("By Language", 0, height)) { auto labels = to_cstr(data.lang_labels); if (!labels.empty()) bar_chart("##lang", labels.data(), data.lang_values.data(), static_cast(labels.size())); } dashboard_panel_end(); dashboard_grid_next(); if (dashboard_panel_begin("By Domain", 0, height)) { auto labels = to_cstr(data.domain_labels); if (!labels.empty()) bar_chart("##domain", labels.data(), data.domain_values.data(), static_cast(labels.size())); } dashboard_panel_end(); dashboard_grid_next(); if (dashboard_panel_begin("Purity", 0, height)) { const char* labels[] = {"Pure", "Impure"}; float values[] = {static_cast(data.stats.pure_functions), static_cast(data.stats.impure_functions)}; pie_chart("##purity", labels, values, 2); } dashboard_panel_end(); dashboard_grid_next(); if (dashboard_panel_begin("Kind", 0, height)) { auto labels = to_cstr(data.kind_labels); if (!labels.empty()) pie_chart("##kind", labels.data(), data.kind_values.data(), static_cast(labels.size())); } dashboard_panel_end(); dashboard_grid_end(); } void draw_recent_functions(const std::vector& funcs) { const char* headers[] = {"Name", "Lang", "Domain", "Kind", "Purity", "Tested", "Created"}; constexpr int cols = 7; std::vector cell_strings; cell_strings.reserve(funcs.size() * cols); for (auto& f : funcs) { cell_strings.push_back(f.name); cell_strings.push_back(f.lang); cell_strings.push_back(f.domain); cell_strings.push_back(f.kind); cell_strings.push_back(f.purity); cell_strings.push_back(f.tested ? "yes" : "no"); cell_strings.push_back(f.created_at.substr(0, 10)); } auto cells = to_cstr(cell_strings); table_view("##recent", headers, cols, cells.data(), static_cast(funcs.size())); } void draw_apps_list(const std::vector& apps) { const char* headers[] = {"Name", "Lang", "Domain", "Framework", "Description"}; constexpr int cols = 5; std::vector cell_strings; cell_strings.reserve(apps.size() * cols); for (auto& a : apps) { cell_strings.push_back(a.name); cell_strings.push_back(a.lang); cell_strings.push_back(a.domain); cell_strings.push_back(a.framework); cell_strings.push_back(a.description); } auto cells = to_cstr(cell_strings); table_view("##apps", headers, cols, cells.data(), static_cast(apps.size())); } void draw_analysis_list(const std::vector& analyses) { const char* headers[] = {"Name", "Domain", "Description"}; constexpr int cols = 3; std::vector cell_strings; cell_strings.reserve(analyses.size() * cols); for (auto& a : analyses) { cell_strings.push_back(a.name); cell_strings.push_back(a.domain); cell_strings.push_back(a.description); } auto cells = to_cstr(cell_strings); table_view("##analysis", headers, cols, cells.data(), static_cast(analyses.size())); } void draw_types_list(const std::vector& types) { const char* headers[] = {"Name", "Lang", "Domain", "Algebraic", "Description"}; constexpr int cols = 5; std::vector cell_strings; cell_strings.reserve(types.size() * cols); for (auto& t : types) { cell_strings.push_back(t.name); cell_strings.push_back(t.lang); cell_strings.push_back(t.domain); cell_strings.push_back(t.algebraic); cell_strings.push_back(t.description); } auto cells = to_cstr(cell_strings); table_view("##types", headers, cols, cells.data(), static_cast(types.size())); } void draw_dashboard(RegistryData& data) { fps_overlay(); fullscreen_window_begin("##dashboard"); float win_h = ImGui::GetContentRegionAvail().y; // Row 1: Header + KPIs (~80px) ImGui::Text("fn_registry Dashboard"); ImGui::SameLine(ImGui::GetWindowWidth() - 100); if (ImGui::Button("Reload")) { ImGui::GetIO().UserData = reinterpret_cast(1); } ImGui::Separator(); draw_kpi_row(data.stats); ImGui::Separator(); // Row 2: Charts — take 35% of remaining height float remaining = ImGui::GetContentRegionAvail().y; float chart_h = remaining * 0.35f; if (chart_h < 150.0f) chart_h = 150.0f; draw_charts(data, chart_h); ImGui::Separator(); // Row 3: Tables — fill the rest if (ImGui::BeginTabBar("##tables")) { if (ImGui::BeginTabItem("Recent Functions")) { draw_recent_functions(data.recent_funcs); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Apps")) { draw_apps_list(data.apps); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Analysis")) { draw_analysis_list(data.analyses); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Types")) { draw_types_list(data.types); ImGui::EndTabItem(); } ImGui::EndTabBar(); } fullscreen_window_end(); }