migrate Monitor Recent Executions + Failed Functions to data_table::render with Badge/Duration renderers (issue 0081-J)
- Replace ##monitor_recent BeginTable (6 cols) with data_table::render: - Duration renderer on duration_ms col (warn=500ms, error=2000ms) - Badge renderer on Status col: ok=#22c55e, error=#ef4444, running=#3b82f6, timeout=#f59e0b - success bool encoded as "ok"/"error" string for badge matching - Replace ##monitor_failed_fns BeginTable (5 cols) with data_table::render: - Badge renderer on Error Class col: sqlite/network/timeout/not_found/auth/parse/io/permission/unknown - empty error_class normalized to "unknown" for badge match - Add g_dt_monitor_recent + g_dt_monitor_failed persistent State members - Remove all inline coloring helpers for these two tables (covered by renderers) - fn doctor cpp-apps: registry_dashboard BeginTable inline count 7 -> 5 (5 remaining are layout splitters: kpi_grid/chart_grid/monitor_kpi/proj_layout/explorer_layout) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -118,6 +118,8 @@ static data_table::State g_dt_vaults;
|
||||
static data_table::State g_dt_top_fn;
|
||||
static data_table::State g_dt_violations;
|
||||
static data_table::State g_dt_copies;
|
||||
static data_table::State g_dt_monitor_recent; // issue 0081-J
|
||||
static data_table::State g_dt_monitor_failed; // issue 0081-J
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers: build a data_table::TableInput from registry row vectors
|
||||
@@ -769,68 +771,83 @@ void draw_monitor(RegistryData& data) {
|
||||
if (cu.recent_executions.empty()) {
|
||||
ImGui::TextDisabled("No executions in this window. Try widening (7d/30d/All) or wait for the next call.");
|
||||
} else {
|
||||
const ImGuiTableFlags tf = ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders
|
||||
| ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY;
|
||||
if (ImGui::BeginTable("##monitor_recent", 6, tf, ImVec2(0, 0))) {
|
||||
ImGui::TableSetupColumn("When");
|
||||
ImGui::TableSetupColumn("Function");
|
||||
ImGui::TableSetupColumn("Tool");
|
||||
ImGui::TableSetupColumn("ms");
|
||||
ImGui::TableSetupColumn("OK");
|
||||
ImGui::TableSetupColumn("Error");
|
||||
ImGui::TableHeadersRow();
|
||||
// Build TableInput for data_table::render (issue 0081-J).
|
||||
// Columns: When | Function | Tool | Duration(ms) | Status
|
||||
// Status = "ok" | "error" (from r.success) → Badge renderer.
|
||||
// Duration → Duration renderer (warn=500ms, error=2000ms).
|
||||
data_table::TableInput ti;
|
||||
ti.name = "monitor_recent";
|
||||
ti.headers = {"When", "Function", "Tool", "Duration", "Status"};
|
||||
ti.types = {
|
||||
data_table::ColumnType::String,
|
||||
data_table::ColumnType::String,
|
||||
data_table::ColumnType::String,
|
||||
data_table::ColumnType::Float,
|
||||
data_table::ColumnType::String,
|
||||
};
|
||||
|
||||
// column_specs: parallel to headers (5 specs)
|
||||
ti.column_specs.resize(5);
|
||||
// col 0 When: Text (default)
|
||||
ti.column_specs[0].renderer = data_table::CellRenderer::Text;
|
||||
// col 1 Function: Text (default)
|
||||
ti.column_specs[1].renderer = data_table::CellRenderer::Text;
|
||||
// col 2 Tool: Text (default)
|
||||
ti.column_specs[2].renderer = data_table::CellRenderer::Text;
|
||||
// col 3 Duration: Duration renderer
|
||||
ti.column_specs[3].renderer = data_table::CellRenderer::Duration;
|
||||
ti.column_specs[3].duration_warn_ms = 500.0f;
|
||||
ti.column_specs[3].duration_error_ms = 2000.0f;
|
||||
// col 4 Status: Badge renderer
|
||||
ti.column_specs[4].renderer = data_table::CellRenderer::Badge;
|
||||
ti.column_specs[4].badges = {
|
||||
{"ok", "#22c55e", "OK"},
|
||||
{"error", "#ef4444", "Error"},
|
||||
{"running", "#3b82f6", "Running"},
|
||||
{"timeout", "#f59e0b", "Timeout"},
|
||||
};
|
||||
|
||||
std::vector<std::string> backing;
|
||||
backing.reserve(cu.recent_executions.size() * 5);
|
||||
char dur_buf[24];
|
||||
for (const auto& r : cu.recent_executions) {
|
||||
if (g_recent_only_registry && r.function_id.empty()) continue;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TextUnformatted(format_ts(r.ts).c_str());
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
// When
|
||||
backing.push_back(format_ts(r.ts));
|
||||
// Function — registry call or $ snippet or "-"
|
||||
if (!r.function_id.empty()) {
|
||||
// Call de registry — destacada en color normal.
|
||||
ImGui::TextUnformatted(r.function_id.c_str());
|
||||
backing.push_back(r.function_id);
|
||||
} else if (!r.command_snippet.empty()) {
|
||||
// Tool generica (Bash/heredoc): muestra prefijo `$` + snippet
|
||||
// truncado en muted para distinguirla visualmente de calls registry.
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::text_muted);
|
||||
// Truncado visual a ~80 chars para no romper layout.
|
||||
char buf[88];
|
||||
std::snprintf(buf, sizeof(buf), "$ %.80s%s",
|
||||
char sbuf[88];
|
||||
std::snprintf(sbuf, sizeof(sbuf), "$ %.80s%s",
|
||||
r.command_snippet.c_str(),
|
||||
r.command_snippet.size() > 80 ? "..." : "");
|
||||
ImGui::TextUnformatted(buf);
|
||||
// Hover tooltip con snippet completo (hasta 200 chars).
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(560.0f);
|
||||
ImGui::TextUnformatted(r.command_snippet.c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
backing.push_back(sbuf);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::text_muted);
|
||||
ImGui::TextUnformatted("-");
|
||||
ImGui::PopStyleColor();
|
||||
backing.push_back("-");
|
||||
}
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
ImGui::TextUnformatted(r.tool_used.c_str());
|
||||
ImGui::TableSetColumnIndex(3);
|
||||
ImGui::Text("%d", r.duration_ms);
|
||||
ImGui::TableSetColumnIndex(4);
|
||||
if (r.success) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::success);
|
||||
ImGui::TextUnformatted(TI_CHECK);
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::error);
|
||||
ImGui::TextUnformatted(TI_X);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::TableSetColumnIndex(5);
|
||||
ImGui::TextUnformatted(r.error_class.c_str());
|
||||
}
|
||||
ImGui::EndTable();
|
||||
// Tool
|
||||
backing.push_back(r.tool_used);
|
||||
// Duration (as numeric string for Float column)
|
||||
std::snprintf(dur_buf, sizeof(dur_buf), "%d", r.duration_ms);
|
||||
backing.push_back(dur_buf);
|
||||
// Status
|
||||
backing.push_back(r.success ? "ok" : "error");
|
||||
}
|
||||
|
||||
int nrows = 0;
|
||||
for (const auto& r : cu.recent_executions)
|
||||
if (!g_recent_only_registry || !r.function_id.empty()) nrows++;
|
||||
ti.rows = nrows;
|
||||
ti.cols = static_cast<int>(ti.headers.size());
|
||||
|
||||
std::vector<const char*> ptrs;
|
||||
cells_to_ptrs(backing, ptrs);
|
||||
ti.cells = ptrs.data();
|
||||
|
||||
ImGui::BeginChild("##monitor_recent_wrap", ImVec2(-1, -1));
|
||||
data_table::render("##dt_monitor_recent", {ti}, g_dt_monitor_recent);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
@@ -926,45 +943,75 @@ void draw_monitor(RegistryData& data) {
|
||||
if (failed.empty()) {
|
||||
ImGui::TextDisabled("No registry-function failures in this window. Healthy.");
|
||||
} else {
|
||||
const ImGuiTableFlags tf = ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders
|
||||
| ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY;
|
||||
if (ImGui::BeginTable("##monitor_failed_fns", 5, tf, ImVec2(0, 0))) {
|
||||
ImGui::TableSetupColumn("When");
|
||||
ImGui::TableSetupColumn("Function");
|
||||
ImGui::TableSetupColumn("Tool");
|
||||
ImGui::TableSetupColumn("Error class");
|
||||
ImGui::TableSetupColumn("Error snippet");
|
||||
ImGui::TableHeadersRow();
|
||||
// Build TableInput for data_table::render (issue 0081-J).
|
||||
// Columns: When | Function | Tool | Error Class | Snippet
|
||||
// Error Class → Badge renderer with common error class colors.
|
||||
data_table::TableInput ti;
|
||||
ti.name = "monitor_failed";
|
||||
ti.headers = {"When", "Function", "Tool", "Error Class", "Snippet"};
|
||||
ti.types = {
|
||||
data_table::ColumnType::String,
|
||||
data_table::ColumnType::String,
|
||||
data_table::ColumnType::String,
|
||||
data_table::ColumnType::String,
|
||||
data_table::ColumnType::String,
|
||||
};
|
||||
|
||||
// column_specs: parallel to headers (5 specs)
|
||||
ti.column_specs.resize(5);
|
||||
// col 0 When: Text (default)
|
||||
ti.column_specs[0].renderer = data_table::CellRenderer::Text;
|
||||
// col 1 Function: Text (default) — already in error context, no extra badge needed
|
||||
ti.column_specs[1].renderer = data_table::CellRenderer::Text;
|
||||
// col 2 Tool: Text (default)
|
||||
ti.column_specs[2].renderer = data_table::CellRenderer::Text;
|
||||
// col 3 Error Class: Badge renderer
|
||||
ti.column_specs[3].renderer = data_table::CellRenderer::Badge;
|
||||
ti.column_specs[3].badges = {
|
||||
{"sqlite", "#f59e0b", "SQLite"},
|
||||
{"network", "#3b82f6", "Network"},
|
||||
{"timeout", "#f59e0b", "Timeout"},
|
||||
{"not_found", "#8b5cf6", "Not Found"},
|
||||
{"auth", "#ef4444", "Auth"},
|
||||
{"parse", "#ec4899", "Parse"},
|
||||
{"io", "#06b6d4", "I/O"},
|
||||
{"permission", "#ef4444", "Permission"},
|
||||
{"unknown", "#6b7280", "Unknown"},
|
||||
};
|
||||
// col 4 Snippet: Text (default)
|
||||
ti.column_specs[4].renderer = data_table::CellRenderer::Text;
|
||||
|
||||
std::vector<std::string> backing;
|
||||
backing.reserve(failed.size() * 5);
|
||||
for (const auto* p : failed) {
|
||||
const auto& r = *p;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0); ImGui::TextUnformatted(format_ts(r.ts).c_str());
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::error);
|
||||
ImGui::TextUnformatted(r.function_id.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::TableSetColumnIndex(2); ImGui::TextUnformatted(r.tool_used.c_str());
|
||||
ImGui::TableSetColumnIndex(3); ImGui::TextUnformatted(r.error_class.c_str());
|
||||
ImGui::TableSetColumnIndex(4);
|
||||
backing.push_back(format_ts(r.ts));
|
||||
backing.push_back(r.function_id);
|
||||
backing.push_back(r.tool_used);
|
||||
// error_class: normalize empty to "unknown" for badge matching
|
||||
backing.push_back(r.error_class.empty() ? "unknown" : r.error_class);
|
||||
// snippet: truncate to ~110 chars for table display
|
||||
if (r.error_snippet.empty()) {
|
||||
ImGui::TextDisabled("-");
|
||||
backing.push_back("-");
|
||||
} else {
|
||||
char buf[120];
|
||||
std::snprintf(buf, sizeof(buf), "%.110s%s",
|
||||
char sbuf[120];
|
||||
std::snprintf(sbuf, sizeof(sbuf), "%.110s%s",
|
||||
r.error_snippet.c_str(),
|
||||
r.error_snippet.size() > 110 ? "..." : "");
|
||||
ImGui::TextUnformatted(buf);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(560.0f);
|
||||
ImGui::TextUnformatted(r.error_snippet.c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
backing.push_back(sbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ti.rows = static_cast<int>(failed.size());
|
||||
ti.cols = static_cast<int>(ti.headers.size());
|
||||
|
||||
std::vector<const char*> ptrs;
|
||||
cells_to_ptrs(backing, ptrs);
|
||||
ti.cells = ptrs.data();
|
||||
|
||||
ImGui::BeginChild("##monitor_failed_wrap", ImVec2(-1, -1));
|
||||
data_table::render("##dt_monitor_failed", {ti}, g_dt_monitor_failed);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user