chore: snapshot WIP previo + flow 0008 + 7 sub-issues (0112-0119)
Snapshot de WIP acumulado de sesiones previas antes de merge wave 1 del flow 0008 (kanban_cpp + agent_runner_api + DoD schema). Incluye: - dev/flows/0008-kanban-cpp-and-agent-workflows.md - dev/issues/0112-0119*.md (7 sub-issues) - WIP previo en cmd/fn/doctor.go, registry/*, modules/, cpp/, etc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
// data_table_drill — drill-down stack + breadcrumb de stages.
|
||||
// Sub-funcion extraida de modules/data_table/data_table.cpp (issue 0107c).
|
||||
//
|
||||
// Rangos de lineas del fuente original:
|
||||
// - make_drill_filter : lineas 699-706
|
||||
// - apply_drill_step : lineas 708-718
|
||||
// - undo_drill_step : lineas 720-730
|
||||
// - drill_up : lineas 732-737
|
||||
// - draw_stage_breadcrumb : lineas 1386-1483
|
||||
// - drill_into : lineas 2898-2919
|
||||
|
||||
#include "viz/data_table_drill.h"
|
||||
#include "core/data_table_types.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace data_table {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// make_drill_filter: crea un Filter Op::Eq para col_idx con el valor dado.
|
||||
// ---------------------------------------------------------------------------
|
||||
Filter make_drill_filter(int col_idx, const std::string& value) {
|
||||
Filter f;
|
||||
f.col = col_idx;
|
||||
f.op = Op::Eq;
|
||||
f.value = value;
|
||||
return f;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// apply_drill_step: inserta step.added en el stage en step.target_stage y
|
||||
// actualiza st.active_stage. Retorna true si el step se aplico correctamente.
|
||||
// ---------------------------------------------------------------------------
|
||||
bool apply_drill_step(State& st, const DrillStep& step) {
|
||||
if (step.target_stage < 0 || step.target_stage >= (int)st.stages.size()) return false;
|
||||
Stage& s = st.stages[step.target_stage];
|
||||
int pos = step.filter_pos;
|
||||
if (pos < 0 || pos > (int)s.filters.size()) return false;
|
||||
s.filters.insert(s.filters.begin() + pos, step.added);
|
||||
st.active_stage = step.target_stage;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// undo_drill_step: elimina el filter insertado por apply_drill_step y restaura
|
||||
// st.active_stage a step.prev_active_stage. Retorna true si se deshizo.
|
||||
// ---------------------------------------------------------------------------
|
||||
bool undo_drill_step(State& st, const DrillStep& step) {
|
||||
if (step.target_stage < 0 || step.target_stage >= (int)st.stages.size()) return false;
|
||||
Stage& s = st.stages[step.target_stage];
|
||||
int pos = step.filter_pos;
|
||||
if (pos < 0 || pos >= (int)s.filters.size()) return false;
|
||||
s.filters.erase(s.filters.begin() + pos);
|
||||
if (step.prev_active_stage >= 0 && step.prev_active_stage < (int)st.stages.size())
|
||||
st.active_stage = step.prev_active_stage;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// drill_up: retrocede st.active_stage en 1 si hay stages previos.
|
||||
// Retorna true si se pudo retroceder.
|
||||
// ---------------------------------------------------------------------------
|
||||
bool drill_up(State& st) {
|
||||
if (st.stages.empty()) return false;
|
||||
if (st.active_stage <= 0) return false;
|
||||
st.active_stage -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// draw_stage_breadcrumb: barra de navegacion de drill con botones < > ^ y
|
||||
// selector de stages. Mutates st.drill_back/forward y st.active_stage.
|
||||
// ---------------------------------------------------------------------------
|
||||
void draw_stage_breadcrumb(State& st) {
|
||||
st.ensure_stage0();
|
||||
|
||||
// Drill history back/forward (fase 10). Botones al inicio.
|
||||
{
|
||||
bool can_back = !st.drill_back.empty();
|
||||
ImGui::BeginDisabled(!can_back);
|
||||
if (ImGui::SmallButton("<##drill_back")) {
|
||||
DrillStep s = st.drill_back.back();
|
||||
st.drill_back.pop_back();
|
||||
if (undo_drill_step(st, s)) {
|
||||
st.drill_forward.push_back(s);
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if (can_back && ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Drill back (%zu)", st.drill_back.size());
|
||||
ImGui::SameLine();
|
||||
bool can_fwd = !st.drill_forward.empty();
|
||||
ImGui::BeginDisabled(!can_fwd);
|
||||
if (ImGui::SmallButton(">##drill_fwd")) {
|
||||
DrillStep s = st.drill_forward.back();
|
||||
st.drill_forward.pop_back();
|
||||
if (apply_drill_step(st, s)) {
|
||||
st.drill_back.push_back(s);
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if (can_fwd && ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Drill forward (%zu)", st.drill_forward.size());
|
||||
ImGui::SameLine();
|
||||
bool can_up = (st.active_stage > 0);
|
||||
ImGui::BeginDisabled(!can_up);
|
||||
if (ImGui::SmallButton("^##drill_up")) drill_up(st);
|
||||
ImGui::EndDisabled();
|
||||
if (can_up && ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Drill up (stage previo, sin perder filters)");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("|");
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
for (int si = 0; si < (int)st.stages.size(); ++si) {
|
||||
if (si > 0) { ImGui::SameLine(); ImGui::TextDisabled(">"); ImGui::SameLine(); }
|
||||
|
||||
bool active = (si == st.active_stage);
|
||||
if (active) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32( 80, 140, 200, 240));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(100, 160, 220, 240));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32( 60, 120, 180, 240));
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32( 70, 70, 90, 200));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32( 90, 90, 120, 220));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32( 55, 55, 75, 220));
|
||||
}
|
||||
|
||||
char label[256];
|
||||
if (si == 0) {
|
||||
std::snprintf(label, sizeof(label), "Raw##stage%d", si);
|
||||
} else {
|
||||
const Stage& s = st.stages[si];
|
||||
std::string desc;
|
||||
for (size_t i = 0; i < s.breakouts.size() && i < 2; ++i) {
|
||||
if (i > 0) desc += ", ";
|
||||
desc += s.breakouts[i];
|
||||
}
|
||||
if (s.breakouts.size() > 2) desc += "...";
|
||||
if (desc.empty())
|
||||
std::snprintf(label, sizeof(label), "Stage %d##s%d", si, si);
|
||||
else
|
||||
std::snprintf(label, sizeof(label), "Stage %d: by %s##s%d",
|
||||
si, desc.c_str(), si);
|
||||
}
|
||||
if (ImGui::Button(label)) st.active_stage = si;
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
if (si > 0) {
|
||||
ImGui::SameLine();
|
||||
char xlbl[32];
|
||||
std::snprintf(xlbl, sizeof(xlbl), "x##rm_s%d", si);
|
||||
if (ImGui::SmallButton(xlbl)) {
|
||||
// borra ese stage y sucesores
|
||||
while ((int)st.stages.size() > si) st.stages.pop_back();
|
||||
if (st.active_stage >= (int)st.stages.size())
|
||||
st.active_stage = (int)st.stages.size() - 1;
|
||||
if (st.active_stage < 0) st.active_stage = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled(">");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton("+ Stage##add_stage")) {
|
||||
st.stages.push_back(Stage{});
|
||||
st.active_stage = (int)st.stages.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// drill_into: API publica. Anade un filter Op::Eq sobre col_name=value al
|
||||
// stage (from_stage - 1) y cambia st.active_stage a ese stage previo.
|
||||
// Graba el step en st.drill_back y limpia st.drill_forward (rama nueva).
|
||||
// ---------------------------------------------------------------------------
|
||||
void drill_into(State& st, int from_stage,
|
||||
const std::string& col_name, const std::string& value,
|
||||
const std::vector<std::string>& prev_input_headers)
|
||||
{
|
||||
if (from_stage <= 0 || from_stage >= (int)st.stages.size()) return;
|
||||
int target = from_stage - 1;
|
||||
int ci = -1;
|
||||
for (size_t i = 0; i < prev_input_headers.size(); ++i) {
|
||||
if (prev_input_headers[i] == col_name) { ci = (int)i; break; }
|
||||
}
|
||||
if (ci < 0) return;
|
||||
|
||||
// Fase 10: graba step en drill_back, limpia forward (rama nueva).
|
||||
DrillStep step;
|
||||
step.target_stage = target;
|
||||
step.filter_pos = (int)st.stages[target].filters.size();
|
||||
step.prev_active_stage = st.active_stage;
|
||||
step.added = make_drill_filter(ci, value);
|
||||
apply_drill_step(st, step);
|
||||
st.drill_back.push_back(step);
|
||||
st.drill_forward.clear();
|
||||
}
|
||||
|
||||
} // namespace data_table
|
||||
Reference in New Issue
Block a user