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:
2026-05-19 00:31:31 +02:00
parent 4a786911cb
commit 1bad5685a1
3 changed files with 81 additions and 88 deletions
+11 -12
View File
@@ -2,21 +2,10 @@
name: dag_engine_ui name: dag_engine_ui
lang: cpp lang: cpp
domain: tools domain: tools
version: 0.1.0
description: "Frontend ImGui para dag_engine. Lista, lanza e inspecciona DAGs con live updates via WS." description: "Frontend ImGui para dag_engine. Lista, lanza e inspecciona DAGs con live updates via WS."
tags: [imgui, dashboard, dag, scheduler, http, websocket] tags: [imgui, dashboard, dag, scheduler, http, websocket]
uses_functions: 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 - empty_state_cpp_core
uses_types: [] uses_types: []
uses_modules: [data_table_cpp] uses_modules: [data_table_cpp]
@@ -77,3 +66,13 @@ cd cpp && cmake --build build --target dag_engine_ui -j
## Backend ## 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)**. 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
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

+70 -76
View File
@@ -371,86 +371,79 @@ void draw_run_detail(const std::string& api_url) {
return; return;
} }
// Steps table — render nativo (ImGui::BeginTable) en vez de data_table::render // Steps table — migrado a data_table::render (issue 0107g).
// para soportar la columna "Function" clickable (badge -> abre Function panel). // La columna Function usa CellRenderer::Button con action_id="open_fn".
// Status sigue mostrando badge coloreado por tipo. // Celdas con function_id="" muestran "(shell)" via Text (no button).
ImGui::BeginChild("##run_steps_wrap", ImVec2(-1, ImGui::GetContentRegionAvail().y * 0.5f)); static data_table::State g_st_run_steps;
const ImGuiTableFlags steps_flags = static std::vector<std::string> g_back_run_steps;
ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | static std::vector<const char*> g_ptrs_run_steps;
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();
for (size_t i = 0; i < steps.size(); i++) { g_back_run_steps.clear();
auto& s = steps[i]; for (const auto& s : steps) {
ImGui::TableNextRow(); g_back_run_steps.push_back(s.step_name);
g_back_run_steps.push_back(s.function_id.empty() ? "(shell)" : s.function_id);
// Step name g_back_run_steps.push_back(s.status);
ImGui::TableSetColumnIndex(0); g_back_run_steps.push_back(std::to_string(s.exit_code));
ImGui::TextUnformatted(s.step_name.c_str()); g_back_run_steps.push_back(format_duration(s.duration_ms));
g_back_run_steps.push_back(s.started_at);
// 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_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(); 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. // stdout/stderr expandible por step.
ImGui::Separator(); ImGui::Separator();
ImGui::TextUnformatted("Step output:"); ImGui::TextUnformatted("Step output:");
@@ -728,6 +721,7 @@ void draw_health(const std::string& /*api_url*/,
return; return;
} }
// LAYOUT-TABLE — KPI/form/splitter, no data; keep BeginTable inline.
if (ImGui::BeginTable("##health_kpis", 4, if (ImGui::BeginTable("##health_kpis", 4,
ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchSame)) ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchSame))
{ {