feat(dashboard): v0.3.0 — Status panel, dashboard_panel/grid, AppConfig pattern
- main.cpp: bump 0.2.0 → 0.3.0; añadir Status section en Settings via settings_window_add_section (fuente API/SQLite, URL, DB path, Reload). - views.cpp: chart_panel manual + BeginChild custom → dashboard_panel/grid del registry. KPI cards con sparkline a la derecha, altura responsive. - views.h: signature de draw_kpi_row pasa RegistryData (para sparkline). - CMakeLists.txt: añadir process_state_machine.cpp (dependencia de process_runner tras issue 0045).
This commit is contained in:
@@ -9,9 +9,9 @@
|
||||
#include "viz/pie_chart.h"
|
||||
#include "viz/table_view.h"
|
||||
#include "viz/sparkline.h"
|
||||
#include "core/icons_tabler.h"
|
||||
#include "core/dashboard_panel.h"
|
||||
#include "core/dashboard_grid.h"
|
||||
#include "core/fps_overlay.h"
|
||||
#include "core/fullscreen_window.h"
|
||||
#include "core/tokens.h"
|
||||
#include "core/page_header.h"
|
||||
@@ -68,7 +68,8 @@ static void trigger_reload() {
|
||||
// KPI row
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void draw_kpi_row(const RegistryStats& stats) {
|
||||
void draw_kpi_row(const RegistryData& data) {
|
||||
const RegistryStats& stats = data.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
|
||||
@@ -77,22 +78,30 @@ void draw_kpi_row(const RegistryStats& stats) {
|
||||
const ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame
|
||||
| ImGuiTableFlags_NoPadOuterX;
|
||||
|
||||
// Sparkline shared: ultimos 30 dias de creacion de funciones (timeline real
|
||||
// del registry). Si no hay datos cargados, queda vacio y el card mostrara
|
||||
// solo valor + delta placeholder.
|
||||
const float* spark_data = data.date_values.empty() ? nullptr : data.date_values.data();
|
||||
const int spark_count = static_cast<int>(data.date_values.size());
|
||||
|
||||
if (ImGui::BeginTable("##kpi_grid", 4, flags)) {
|
||||
struct KPI { const char* label; float value; const char* fmt; };
|
||||
struct KPI { const char* label; float value; const char* fmt; const char* icon; };
|
||||
const KPI cards[8] = {
|
||||
{"Functions", static_cast<float>(stats.total_functions), "%.0f"},
|
||||
{"Types", static_cast<float>(stats.total_types), "%.0f"},
|
||||
{"Apps", static_cast<float>(stats.total_apps), "%.0f"},
|
||||
{"Analysis", static_cast<float>(stats.total_analysis), "%.0f"},
|
||||
{"Unit Tests", static_cast<float>(stats.total_unit_tests), "%.0f"},
|
||||
{"Proposals", static_cast<float>(stats.total_proposals), "%.0f"},
|
||||
{"Tested", tested_pct, "%.0f%%"},
|
||||
{"Pure", pure_pct, "%.0f%%"},
|
||||
{"Functions", static_cast<float>(stats.total_functions), "%.0f", TI_FUNCTION},
|
||||
{"Types", static_cast<float>(stats.total_types), "%.0f", TI_HEXAGON},
|
||||
{"Apps", static_cast<float>(stats.total_apps), "%.0f", TI_APPS},
|
||||
{"Analysis", static_cast<float>(stats.total_analysis), "%.0f", TI_FLASK},
|
||||
{"Unit Tests", static_cast<float>(stats.total_unit_tests), "%.0f", TI_TEST_PIPE},
|
||||
{"Proposals", static_cast<float>(stats.total_proposals), "%.0f", TI_BULB},
|
||||
{"Tested", tested_pct, "%.0f%%", TI_CIRCLE_CHECK},
|
||||
{"Pure", pure_pct, "%.0f%%", TI_HEART},
|
||||
};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i % 4 == 0) ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(i % 4);
|
||||
kpi_card(cards[i].label, cards[i].value, 0.0f, nullptr, 0, cards[i].fmt);
|
||||
kpi_card(cards[i].label, cards[i].value, 0.0f,
|
||||
spark_data, spark_count,
|
||||
cards[i].fmt, cards[i].icon);
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
@@ -587,8 +596,8 @@ static void draw_actions_bar() {
|
||||
|
||||
void draw_dashboard(RegistryData& data) {
|
||||
// Tema aplicado por fn::run_app() (app_base.h, ThemeMode::FnDark default).
|
||||
// FPS overlay lo dibuja app_base.cpp segun settings().show_fps — no llamarlo aqui.
|
||||
|
||||
fps_overlay();
|
||||
fullscreen_window_begin("##dashboard");
|
||||
|
||||
char subtitle[128];
|
||||
@@ -604,10 +613,16 @@ void draw_dashboard(RegistryData& data) {
|
||||
draw_actions_bar();
|
||||
ImGui::Dummy(ImVec2(0, fn_tokens::spacing::sm));
|
||||
|
||||
draw_kpi_row(data.stats);
|
||||
draw_kpi_row(data);
|
||||
ImGui::Dummy(ImVec2(0, fn_tokens::spacing::md));
|
||||
|
||||
constexpr float chart_h = 260.0f;
|
||||
// Altura del bloque de charts proporcional al espacio disponible: ~28% del
|
||||
// espacio restante despues de KPIs/header/tabs (clamped a [200, 360] px
|
||||
// para que ni se aplaste ni domine en pantallas grandes).
|
||||
const float remaining_h = ImGui::GetContentRegionAvail().y;
|
||||
float chart_h = remaining_h * 0.32f;
|
||||
if (chart_h < 200.0f) chart_h = 200.0f;
|
||||
if (chart_h > 360.0f) chart_h = 360.0f;
|
||||
draw_charts(data, chart_h);
|
||||
ImGui::Dummy(ImVec2(0, fn_tokens::spacing::md));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user