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_top_fn;
|
||||||
static data_table::State g_dt_violations;
|
static data_table::State g_dt_violations;
|
||||||
static data_table::State g_dt_copies;
|
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
|
// Helpers: build a data_table::TableInput from registry row vectors
|
||||||
@@ -769,68 +771,83 @@ void draw_monitor(RegistryData& data) {
|
|||||||
if (cu.recent_executions.empty()) {
|
if (cu.recent_executions.empty()) {
|
||||||
ImGui::TextDisabled("No executions in this window. Try widening (7d/30d/All) or wait for the next call.");
|
ImGui::TextDisabled("No executions in this window. Try widening (7d/30d/All) or wait for the next call.");
|
||||||
} else {
|
} else {
|
||||||
const ImGuiTableFlags tf = ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders
|
// Build TableInput for data_table::render (issue 0081-J).
|
||||||
| ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY;
|
// Columns: When | Function | Tool | Duration(ms) | Status
|
||||||
if (ImGui::BeginTable("##monitor_recent", 6, tf, ImVec2(0, 0))) {
|
// Status = "ok" | "error" (from r.success) → Badge renderer.
|
||||||
ImGui::TableSetupColumn("When");
|
// Duration → Duration renderer (warn=500ms, error=2000ms).
|
||||||
ImGui::TableSetupColumn("Function");
|
data_table::TableInput ti;
|
||||||
ImGui::TableSetupColumn("Tool");
|
ti.name = "monitor_recent";
|
||||||
ImGui::TableSetupColumn("ms");
|
ti.headers = {"When", "Function", "Tool", "Duration", "Status"};
|
||||||
ImGui::TableSetupColumn("OK");
|
ti.types = {
|
||||||
ImGui::TableSetupColumn("Error");
|
data_table::ColumnType::String,
|
||||||
ImGui::TableHeadersRow();
|
data_table::ColumnType::String,
|
||||||
for (const auto& r : cu.recent_executions) {
|
data_table::ColumnType::String,
|
||||||
if (g_recent_only_registry && r.function_id.empty()) continue;
|
data_table::ColumnType::Float,
|
||||||
ImGui::TableNextRow();
|
data_table::ColumnType::String,
|
||||||
ImGui::TableSetColumnIndex(0);
|
};
|
||||||
ImGui::TextUnformatted(format_ts(r.ts).c_str());
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
// column_specs: parallel to headers (5 specs)
|
||||||
if (!r.function_id.empty()) {
|
ti.column_specs.resize(5);
|
||||||
// Call de registry — destacada en color normal.
|
// col 0 When: Text (default)
|
||||||
ImGui::TextUnformatted(r.function_id.c_str());
|
ti.column_specs[0].renderer = data_table::CellRenderer::Text;
|
||||||
} else if (!r.command_snippet.empty()) {
|
// col 1 Function: Text (default)
|
||||||
// Tool generica (Bash/heredoc): muestra prefijo `$` + snippet
|
ti.column_specs[1].renderer = data_table::CellRenderer::Text;
|
||||||
// truncado en muted para distinguirla visualmente de calls registry.
|
// col 2 Tool: Text (default)
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::text_muted);
|
ti.column_specs[2].renderer = data_table::CellRenderer::Text;
|
||||||
// Truncado visual a ~80 chars para no romper layout.
|
// col 3 Duration: Duration renderer
|
||||||
char buf[88];
|
ti.column_specs[3].renderer = data_table::CellRenderer::Duration;
|
||||||
std::snprintf(buf, sizeof(buf), "$ %.80s%s",
|
ti.column_specs[3].duration_warn_ms = 500.0f;
|
||||||
r.command_snippet.c_str(),
|
ti.column_specs[3].duration_error_ms = 2000.0f;
|
||||||
r.command_snippet.size() > 80 ? "..." : "");
|
// col 4 Status: Badge renderer
|
||||||
ImGui::TextUnformatted(buf);
|
ti.column_specs[4].renderer = data_table::CellRenderer::Badge;
|
||||||
// Hover tooltip con snippet completo (hasta 200 chars).
|
ti.column_specs[4].badges = {
|
||||||
if (ImGui::IsItemHovered()) {
|
{"ok", "#22c55e", "OK"},
|
||||||
ImGui::BeginTooltip();
|
{"error", "#ef4444", "Error"},
|
||||||
ImGui::PushTextWrapPos(560.0f);
|
{"running", "#3b82f6", "Running"},
|
||||||
ImGui::TextUnformatted(r.command_snippet.c_str());
|
{"timeout", "#f59e0b", "Timeout"},
|
||||||
ImGui::PopTextWrapPos();
|
};
|
||||||
ImGui::EndTooltip();
|
|
||||||
}
|
std::vector<std::string> backing;
|
||||||
ImGui::PopStyleColor();
|
backing.reserve(cu.recent_executions.size() * 5);
|
||||||
} else {
|
char dur_buf[24];
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::text_muted);
|
for (const auto& r : cu.recent_executions) {
|
||||||
ImGui::TextUnformatted("-");
|
if (g_recent_only_registry && r.function_id.empty()) continue;
|
||||||
ImGui::PopStyleColor();
|
// When
|
||||||
}
|
backing.push_back(format_ts(r.ts));
|
||||||
ImGui::TableSetColumnIndex(2);
|
// Function — registry call or $ snippet or "-"
|
||||||
ImGui::TextUnformatted(r.tool_used.c_str());
|
if (!r.function_id.empty()) {
|
||||||
ImGui::TableSetColumnIndex(3);
|
backing.push_back(r.function_id);
|
||||||
ImGui::Text("%d", r.duration_ms);
|
} else if (!r.command_snippet.empty()) {
|
||||||
ImGui::TableSetColumnIndex(4);
|
char sbuf[88];
|
||||||
if (r.success) {
|
std::snprintf(sbuf, sizeof(sbuf), "$ %.80s%s",
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::success);
|
r.command_snippet.c_str(),
|
||||||
ImGui::TextUnformatted(TI_CHECK);
|
r.command_snippet.size() > 80 ? "..." : "");
|
||||||
ImGui::PopStyleColor();
|
backing.push_back(sbuf);
|
||||||
} else {
|
} else {
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::error);
|
backing.push_back("-");
|
||||||
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();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
@@ -926,45 +943,75 @@ void draw_monitor(RegistryData& data) {
|
|||||||
if (failed.empty()) {
|
if (failed.empty()) {
|
||||||
ImGui::TextDisabled("No registry-function failures in this window. Healthy.");
|
ImGui::TextDisabled("No registry-function failures in this window. Healthy.");
|
||||||
} else {
|
} else {
|
||||||
const ImGuiTableFlags tf = ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders
|
// Build TableInput for data_table::render (issue 0081-J).
|
||||||
| ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY;
|
// Columns: When | Function | Tool | Error Class | Snippet
|
||||||
if (ImGui::BeginTable("##monitor_failed_fns", 5, tf, ImVec2(0, 0))) {
|
// Error Class → Badge renderer with common error class colors.
|
||||||
ImGui::TableSetupColumn("When");
|
data_table::TableInput ti;
|
||||||
ImGui::TableSetupColumn("Function");
|
ti.name = "monitor_failed";
|
||||||
ImGui::TableSetupColumn("Tool");
|
ti.headers = {"When", "Function", "Tool", "Error Class", "Snippet"};
|
||||||
ImGui::TableSetupColumn("Error class");
|
ti.types = {
|
||||||
ImGui::TableSetupColumn("Error snippet");
|
data_table::ColumnType::String,
|
||||||
ImGui::TableHeadersRow();
|
data_table::ColumnType::String,
|
||||||
for (const auto* p : failed) {
|
data_table::ColumnType::String,
|
||||||
const auto& r = *p;
|
data_table::ColumnType::String,
|
||||||
ImGui::TableNextRow();
|
data_table::ColumnType::String,
|
||||||
ImGui::TableSetColumnIndex(0); ImGui::TextUnformatted(format_ts(r.ts).c_str());
|
};
|
||||||
ImGui::TableSetColumnIndex(1);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, fn_tokens::colors::error);
|
// column_specs: parallel to headers (5 specs)
|
||||||
ImGui::TextUnformatted(r.function_id.c_str());
|
ti.column_specs.resize(5);
|
||||||
ImGui::PopStyleColor();
|
// col 0 When: Text (default)
|
||||||
ImGui::TableSetColumnIndex(2); ImGui::TextUnformatted(r.tool_used.c_str());
|
ti.column_specs[0].renderer = data_table::CellRenderer::Text;
|
||||||
ImGui::TableSetColumnIndex(3); ImGui::TextUnformatted(r.error_class.c_str());
|
// col 1 Function: Text (default) — already in error context, no extra badge needed
|
||||||
ImGui::TableSetColumnIndex(4);
|
ti.column_specs[1].renderer = data_table::CellRenderer::Text;
|
||||||
if (r.error_snippet.empty()) {
|
// col 2 Tool: Text (default)
|
||||||
ImGui::TextDisabled("-");
|
ti.column_specs[2].renderer = data_table::CellRenderer::Text;
|
||||||
} else {
|
// col 3 Error Class: Badge renderer
|
||||||
char buf[120];
|
ti.column_specs[3].renderer = data_table::CellRenderer::Badge;
|
||||||
std::snprintf(buf, sizeof(buf), "%.110s%s",
|
ti.column_specs[3].badges = {
|
||||||
r.error_snippet.c_str(),
|
{"sqlite", "#f59e0b", "SQLite"},
|
||||||
r.error_snippet.size() > 110 ? "..." : "");
|
{"network", "#3b82f6", "Network"},
|
||||||
ImGui::TextUnformatted(buf);
|
{"timeout", "#f59e0b", "Timeout"},
|
||||||
if (ImGui::IsItemHovered()) {
|
{"not_found", "#8b5cf6", "Not Found"},
|
||||||
ImGui::BeginTooltip();
|
{"auth", "#ef4444", "Auth"},
|
||||||
ImGui::PushTextWrapPos(560.0f);
|
{"parse", "#ec4899", "Parse"},
|
||||||
ImGui::TextUnformatted(r.error_snippet.c_str());
|
{"io", "#06b6d4", "I/O"},
|
||||||
ImGui::PopTextWrapPos();
|
{"permission", "#ef4444", "Permission"},
|
||||||
ImGui::EndTooltip();
|
{"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;
|
||||||
|
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()) {
|
||||||
|
backing.push_back("-");
|
||||||
|
} else {
|
||||||
|
char sbuf[120];
|
||||||
|
std::snprintf(sbuf, sizeof(sbuf), "%.110s%s",
|
||||||
|
r.error_snippet.c_str(),
|
||||||
|
r.error_snippet.size() > 110 ? "..." : "");
|
||||||
|
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();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user