chore: auto-commit (3 archivos)
- app.md - appicon.ico - tabs.cpp Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,21 +2,10 @@
|
||||
name: dag_engine_ui
|
||||
lang: cpp
|
||||
domain: tools
|
||||
version: 0.1.0
|
||||
description: "Frontend ImGui para dag_engine. Lista, lanza e inspecciona DAGs con live updates via WS."
|
||||
tags: [imgui, dashboard, dag, scheduler, http, websocket]
|
||||
uses_functions:
|
||||
- data_table_cpp_viz
|
||||
- viz_render_cpp_viz
|
||||
- compute_stage_cpp_core
|
||||
- compute_pipeline_cpp_core
|
||||
- compute_column_stats_cpp_core
|
||||
- auto_detect_type_cpp_core
|
||||
- tql_emit_cpp_core
|
||||
- tql_apply_cpp_core
|
||||
- lua_engine_cpp_core
|
||||
- join_tables_cpp_core
|
||||
- tql_to_sql_cpp_core
|
||||
- llm_anthropic_cpp_core
|
||||
- empty_state_cpp_core
|
||||
uses_types: []
|
||||
uses_modules: [data_table_cpp]
|
||||
@@ -77,3 +66,13 @@ cd cpp && cmake --build build --target dag_engine_ui -j
|
||||
## Backend
|
||||
|
||||
Apunta a `http://127.0.0.1:8090` (dag_engine.service via systemd user unit). Para usuario / formato de DAG / troubleshooting: **[apps/dag_engine/README.md](../../apps/dag_engine/README.md)**.
|
||||
|
||||
|
||||
## Capability growth log
|
||||
|
||||
Una linea por bump SemVer. Bump-type segun `.claude/commands/version.md`:
|
||||
- `major`: breaking observable (CLI args, schema BBDD propia, formato wire).
|
||||
- `minor`: feature aditiva (nuevo panel, endpoint, opcion).
|
||||
- `patch`: bugfix sin cambio observable.
|
||||
|
||||
- v0.1.0 (2026-05-18) — baseline.
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 9.3 KiB |
@@ -371,86 +371,79 @@ void draw_run_detail(const std::string& api_url) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Steps table — render nativo (ImGui::BeginTable) en vez de data_table::render
|
||||
// para soportar la columna "Function" clickable (badge -> abre Function panel).
|
||||
// Status sigue mostrando badge coloreado por tipo.
|
||||
ImGui::BeginChild("##run_steps_wrap", ImVec2(-1, ImGui::GetContentRegionAvail().y * 0.5f));
|
||||
const ImGuiTableFlags steps_flags =
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingStretchProp |
|
||||
ImGuiTableFlags_ScrollY;
|
||||
if (ImGui::BeginTable("##dt_run_steps", 6, steps_flags)) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("Step", ImGuiTableColumnFlags_WidthStretch, 1.6f);
|
||||
ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_WidthStretch, 2.2f);
|
||||
ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 0.8f);
|
||||
ImGui::TableSetupColumn("Exit", ImGuiTableColumnFlags_WidthStretch, 0.4f);
|
||||
ImGui::TableSetupColumn("Duration", ImGuiTableColumnFlags_WidthStretch, 0.7f);
|
||||
ImGui::TableSetupColumn("Started", ImGuiTableColumnFlags_WidthStretch, 1.2f);
|
||||
ImGui::TableHeadersRow();
|
||||
// Steps table — migrado a data_table::render (issue 0107g).
|
||||
// La columna Function usa CellRenderer::Button con action_id="open_fn".
|
||||
// Celdas con function_id="" muestran "(shell)" via Text (no button).
|
||||
static data_table::State g_st_run_steps;
|
||||
static std::vector<std::string> g_back_run_steps;
|
||||
static std::vector<const char*> g_ptrs_run_steps;
|
||||
|
||||
for (size_t i = 0; i < steps.size(); i++) {
|
||||
auto& s = steps[i];
|
||||
ImGui::TableNextRow();
|
||||
|
||||
// Step name
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TextUnformatted(s.step_name.c_str());
|
||||
|
||||
// Function — badge clickable o "(shell)"
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
if (!s.function_id.empty()) {
|
||||
ImGui::PushID(static_cast<int>(i));
|
||||
// Small button styled like a badge (registry green).
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.13f, 0.55f, 0.30f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.18f, 0.65f, 0.38f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.10f, 0.45f, 0.25f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 1, 1, 1));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 1));
|
||||
char btn[512];
|
||||
std::snprintf(btn, sizeof(btn), "%s %s", TI_FUNCTION, s.function_id.c_str());
|
||||
if (ImGui::SmallButton(btn)) {
|
||||
auto& fp = function_panel();
|
||||
if (!fp.selected_id.empty() && fp.selected_id != s.function_id) {
|
||||
fp.breadcrumb.push_back(fp.selected_id);
|
||||
}
|
||||
fp.selected_id = s.function_id;
|
||||
fp.loaded = false;
|
||||
fp.load_error.clear();
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor(4);
|
||||
ImGui::PopID();
|
||||
} else {
|
||||
ImGui::TextDisabled("(shell)");
|
||||
}
|
||||
|
||||
// Status badge
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
BadgeVariant v = BadgeVariant::Default;
|
||||
if (s.status == "success") v = BadgeVariant::Success;
|
||||
else if (s.status == "failed") v = BadgeVariant::Error;
|
||||
else if (s.status == "running") v = BadgeVariant::Warning;
|
||||
else if (s.status == "cancelled") v = BadgeVariant::Default;
|
||||
else if (s.status == "pending") v = BadgeVariant::Info;
|
||||
badge(s.status.c_str(), v);
|
||||
|
||||
// Exit
|
||||
ImGui::TableSetColumnIndex(3);
|
||||
ImGui::Text("%d", s.exit_code);
|
||||
|
||||
// Duration
|
||||
ImGui::TableSetColumnIndex(4);
|
||||
ImGui::TextUnformatted(format_duration(s.duration_ms).c_str());
|
||||
|
||||
// Started
|
||||
ImGui::TableSetColumnIndex(5);
|
||||
ImGui::TextUnformatted(s.started_at.c_str());
|
||||
}
|
||||
ImGui::EndTable();
|
||||
g_back_run_steps.clear();
|
||||
for (const auto& s : steps) {
|
||||
g_back_run_steps.push_back(s.step_name);
|
||||
g_back_run_steps.push_back(s.function_id.empty() ? "(shell)" : s.function_id);
|
||||
g_back_run_steps.push_back(s.status);
|
||||
g_back_run_steps.push_back(std::to_string(s.exit_code));
|
||||
g_back_run_steps.push_back(format_duration(s.duration_ms));
|
||||
g_back_run_steps.push_back(s.started_at);
|
||||
}
|
||||
g_ptrs_run_steps.clear();
|
||||
for (const auto& sv : g_back_run_steps) g_ptrs_run_steps.push_back(sv.c_str());
|
||||
|
||||
data_table::TableInput tbl_steps;
|
||||
tbl_steps.name = "dt_run_steps";
|
||||
tbl_steps.headers = {"Step", "Function", "Status", "Exit", "Duration", "Started"};
|
||||
tbl_steps.types = {
|
||||
data_table::ColumnType::String, data_table::ColumnType::String,
|
||||
data_table::ColumnType::String, data_table::ColumnType::Int,
|
||||
data_table::ColumnType::String, data_table::ColumnType::String,
|
||||
};
|
||||
tbl_steps.cells = g_ptrs_run_steps.empty() ? nullptr : g_ptrs_run_steps.data();
|
||||
tbl_steps.rows = (int)steps.size();
|
||||
tbl_steps.cols = 6;
|
||||
|
||||
tbl_steps.column_specs.resize(tbl_steps.cols);
|
||||
for (int i = 0; i < tbl_steps.cols; i++) tbl_steps.column_specs[i].id = tbl_steps.headers[i];
|
||||
// Function → Button (celdas "(shell)" no son function_ids — se ven como texto si label=value)
|
||||
tbl_steps.column_specs[1].renderer = data_table::CellRenderer::Button;
|
||||
tbl_steps.column_specs[1].button_action = "open_fn";
|
||||
tbl_steps.column_specs[1].button_label = ""; // "" → usa valor de celda como label
|
||||
tbl_steps.column_specs[1].button_color_hex = "#21882b";
|
||||
tbl_steps.column_specs[1].tooltip = "Open in Function panel";
|
||||
tbl_steps.column_specs[1].tooltip_on_hover = true;
|
||||
// Status → CategoricalChip
|
||||
tbl_steps.column_specs[2].renderer = data_table::CellRenderer::CategoricalChip;
|
||||
tbl_steps.column_specs[2].chips = {
|
||||
{"success", "#22c55e"},
|
||||
{"failed", "#ef4444"},
|
||||
{"running", "#f59e0b"},
|
||||
{"cancelled", "#a3a3a3"},
|
||||
{"pending", "#3b82f6"},
|
||||
};
|
||||
// Duration → Duration renderer
|
||||
tbl_steps.column_specs[4].renderer = data_table::CellRenderer::Duration;
|
||||
tbl_steps.column_specs[4].duration_warn_ms = 5000.0f;
|
||||
tbl_steps.column_specs[4].duration_error_ms = 30000.0f;
|
||||
|
||||
std::vector<data_table::TableEvent> step_events;
|
||||
ImGui::BeginChild("##run_steps_wrap", ImVec2(-1, ImGui::GetContentRegionAvail().y * 0.5f));
|
||||
data_table::render("##dt_run_steps", {tbl_steps}, g_st_run_steps, &step_events);
|
||||
ImGui::EndChild();
|
||||
|
||||
for (const auto& ev : step_events) {
|
||||
if (ev.kind == data_table::TableEventKind::ButtonClick
|
||||
&& ev.action_id == "open_fn"
|
||||
&& ev.value != "(shell)") {
|
||||
auto& fp = function_panel();
|
||||
if (!fp.selected_id.empty() && fp.selected_id != ev.value) {
|
||||
fp.breadcrumb.push_back(fp.selected_id);
|
||||
}
|
||||
fp.selected_id = ev.value;
|
||||
fp.loaded = false;
|
||||
fp.load_error.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// stdout/stderr expandible por step.
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted("Step output:");
|
||||
@@ -728,6 +721,7 @@ void draw_health(const std::string& /*api_url*/,
|
||||
return;
|
||||
}
|
||||
|
||||
// LAYOUT-TABLE — KPI/form/splitter, no data; keep BeginTable inline.
|
||||
if (ImGui::BeginTable("##health_kpis", 4,
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchSame))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user