b15106fc09
- CMakeLists.txt - app.md - appicon.ico - main.cpp - perf_tests.cpp - perf_tests.h - qa_panel.cpp - qa_panel.h - qa_state.cpp - qa_state.h - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
297 lines
11 KiB
C++
297 lines
11 KiB
C++
// tab_compat — Version selector + side-by-side rendering (simulación educativa).
|
||
// Muestra la MISMA TableInput renderizada dos veces con distinta ColumnSpec config:
|
||
// Left panel : full renderers (v2.1 current).
|
||
// Right panel : renderers degradados según la versión simulada seleccionada.
|
||
//
|
||
// Issue 0108 fase 2. Patrón: tab_renderers.cpp.
|
||
// NOTA: esto es una SIMULACIÓN educativa del compat mode futuro.
|
||
// El compat real requiere flag en el módulo (TBD issue futuro).
|
||
|
||
#include "tabs.h"
|
||
#include "qa_state.h"
|
||
#include "data_table/data_table.h"
|
||
#include <imgui.h>
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
namespace tables_qa::tabs {
|
||
|
||
namespace {
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Datos: 8 filas × 5 cols (id, name, status, duration_ms, priority).
|
||
// ---------------------------------------------------------------------------
|
||
qa::TabState g_left; // panel izquierdo — full config v2.1
|
||
qa::TabState g_right; // panel derecho — config degradada
|
||
|
||
static const char* k_headers[] = { "id", "name", "status", "duration_ms", "priority" };
|
||
static const int k_cols = 5;
|
||
static const int k_rows = 8;
|
||
|
||
// backing strings: row-major id/name/status/duration_ms/priority
|
||
static const char* k_cells_raw[k_rows * k_cols] = {
|
||
"1", "auth_service", "ok", "320", "high",
|
||
"2", "db_sync", "error", "4800", "critical",
|
||
"3", "cache_warmup", "running", "750", "medium",
|
||
"4", "report_gen", "pending", "2100", "low",
|
||
"5", "email_dispatch", "ok", "180", "high",
|
||
"6", "index_rebuild", "error", "5900", "critical",
|
||
"7", "metrics_collector", "running", "950", "medium",
|
||
"8", "snapshot_export", "pending", "1500", "low",
|
||
};
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Versiones simuladas
|
||
// ---------------------------------------------------------------------------
|
||
enum class SimVersion {
|
||
V21 = 0, // v2.1.0 — full renderers
|
||
V20 = 1, // v2.0.0 — full renderers, solo split refactor
|
||
V15 = 2, // v1.5.0 — no CategoricalChip → fallback Text en status
|
||
V14 = 3, // v1.4.0 — no Dots, no CategoricalChip, no ColorScale → Badge básico
|
||
};
|
||
|
||
static const char* k_version_labels[] = {
|
||
"v2.1.0 (current)",
|
||
"v2.0.0 (split refactor, MODE: no renderer config)",
|
||
"v1.5.0 (legacy, MODE: no CategoricalChip)",
|
||
"v1.4.0 (legacy, MODE: no Dots + no ColorScale)",
|
||
};
|
||
static int g_selected_version = 0;
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Construir TableInput — cabeceras + tipos + punteros a datos estáticos.
|
||
// ColumnSpec se rellena por cada panel por separado.
|
||
// ---------------------------------------------------------------------------
|
||
static data_table::TableInput make_base_table(const char* tbl_name) {
|
||
data_table::TableInput t;
|
||
t.name = tbl_name;
|
||
t.headers = { "id", "name", "status", "duration_ms", "priority" };
|
||
t.types = {
|
||
data_table::ColumnType::Int,
|
||
data_table::ColumnType::String,
|
||
data_table::ColumnType::String,
|
||
data_table::ColumnType::Float,
|
||
data_table::ColumnType::String,
|
||
};
|
||
t.cells = k_cells_raw;
|
||
t.rows = k_rows;
|
||
t.cols = k_cols;
|
||
return t;
|
||
}
|
||
|
||
// Specifica las reglas de CategoricalChip para la col status
|
||
static void apply_status_chip(data_table::ColumnSpec& cs) {
|
||
cs.renderer = data_table::CellRenderer::CategoricalChip;
|
||
cs.chips = {
|
||
{ "ok", "#22c55e" },
|
||
{ "error", "#ef4444" },
|
||
{ "running", "#f59e0b" },
|
||
{ "pending", "#a3a3a3" },
|
||
};
|
||
}
|
||
|
||
// Specifica Badge básico (fallback sin CategoricalChip)
|
||
static void apply_status_badge(data_table::ColumnSpec& cs) {
|
||
cs.renderer = data_table::CellRenderer::Badge;
|
||
cs.badges = {
|
||
{ "ok", "#22c55e", "" },
|
||
{ "error", "#ef4444", "ERR" },
|
||
{ "running", "#f59e0b", "RUN" },
|
||
{ "pending", "#a3a3a3", "..." },
|
||
};
|
||
}
|
||
|
||
// Aplica specs para panel LEFT — siempre v2.1 full
|
||
static void apply_full_specs(data_table::TableInput& t) {
|
||
t.column_specs.resize(k_cols);
|
||
for (int i = 0; i < k_cols; i++) t.column_specs[i].id = k_headers[i];
|
||
|
||
// col 0: id — Text (default)
|
||
// col 1: name — Text (default)
|
||
|
||
// col 2: status — CategoricalChip
|
||
apply_status_chip(t.column_specs[2]);
|
||
|
||
// col 3: duration_ms — Duration renderer
|
||
{
|
||
auto& cs = t.column_specs[3];
|
||
cs.renderer = data_table::CellRenderer::Duration;
|
||
cs.duration_warn_ms = 1000.0f;
|
||
cs.duration_error_ms = 5000.0f;
|
||
}
|
||
|
||
// col 4: priority — ColorScale
|
||
{
|
||
auto& cs = t.column_specs[4];
|
||
cs.renderer = data_table::CellRenderer::ColorScale;
|
||
cs.range_min = 0.0;
|
||
cs.range_max = 4.0;
|
||
cs.range_alpha = 0.30f;
|
||
// stops: low (green) → medium (amber) → high/critical (red)
|
||
cs.range_stops = {
|
||
{ 0.0f, "#22c55e" },
|
||
{ 0.5f, "#f59e0b" },
|
||
{ 1.0f, "#ef4444" },
|
||
};
|
||
}
|
||
}
|
||
|
||
// Aplica specs para panel RIGHT — degradado según versión seleccionada
|
||
static void apply_downgraded_specs(data_table::TableInput& t, SimVersion ver) {
|
||
t.column_specs.resize(k_cols);
|
||
for (int i = 0; i < k_cols; i++) t.column_specs[i].id = k_headers[i];
|
||
|
||
switch (ver) {
|
||
case SimVersion::V21:
|
||
// Igual que full (no debería llegar aquí, pero por completitud)
|
||
apply_full_specs(t);
|
||
break;
|
||
|
||
case SimVersion::V20:
|
||
// v2.0.0: full renderers disponibles, mismo resultado visual.
|
||
// La diferencia real es interna (split refactor en el módulo).
|
||
// Simulamos: idéntico a v2.1.
|
||
apply_status_chip(t.column_specs[2]);
|
||
{
|
||
auto& cs = t.column_specs[3];
|
||
cs.renderer = data_table::CellRenderer::Duration;
|
||
cs.duration_warn_ms = 1000.0f;
|
||
cs.duration_error_ms = 5000.0f;
|
||
}
|
||
{
|
||
auto& cs = t.column_specs[4];
|
||
cs.renderer = data_table::CellRenderer::ColorScale;
|
||
cs.range_min = 0.0;
|
||
cs.range_max = 4.0;
|
||
cs.range_alpha = 0.30f;
|
||
cs.range_stops = {
|
||
{ 0.0f, "#22c55e" },
|
||
{ 0.5f, "#f59e0b" },
|
||
{ 1.0f, "#ef4444" },
|
||
};
|
||
}
|
||
break;
|
||
|
||
case SimVersion::V15:
|
||
// v1.5.0: CategoricalChip no disponible → fallback Badge en status.
|
||
// Duration + ColorScale sí disponibles.
|
||
apply_status_badge(t.column_specs[2]);
|
||
{
|
||
auto& cs = t.column_specs[3];
|
||
cs.renderer = data_table::CellRenderer::Duration;
|
||
cs.duration_warn_ms = 1000.0f;
|
||
cs.duration_error_ms = 5000.0f;
|
||
}
|
||
{
|
||
auto& cs = t.column_specs[4];
|
||
cs.renderer = data_table::CellRenderer::ColorScale;
|
||
cs.range_min = 0.0;
|
||
cs.range_max = 4.0;
|
||
cs.range_alpha = 0.30f;
|
||
cs.range_stops = {
|
||
{ 0.0f, "#22c55e" },
|
||
{ 0.5f, "#f59e0b" },
|
||
{ 1.0f, "#ef4444" },
|
||
};
|
||
}
|
||
break;
|
||
|
||
case SimVersion::V14:
|
||
// v1.4.0: ni CategoricalChip, ni ColorScale → Badge básico en status,
|
||
// Duration degradada (Badge de rango), priority Text plano.
|
||
apply_status_badge(t.column_specs[2]);
|
||
// Duration: sin renderer específico → solo Text
|
||
t.column_specs[3].renderer = data_table::CellRenderer::Text;
|
||
// priority: Text plano
|
||
t.column_specs[4].renderer = data_table::CellRenderer::Text;
|
||
break;
|
||
}
|
||
}
|
||
|
||
} // anon
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// render_compat — entry point
|
||
// ---------------------------------------------------------------------------
|
||
void render_compat() {
|
||
// ---- Cabecera de controles ----
|
||
ImGui::TextDisabled("Active module: data_table v2.1.0");
|
||
ImGui::SameLine();
|
||
ImGui::Spacing();
|
||
ImGui::SameLine();
|
||
ImGui::SetNextItemWidth(360.0f);
|
||
ImGui::Combo("Compare with version", &g_selected_version,
|
||
k_version_labels, IM_ARRAYSIZE(k_version_labels));
|
||
|
||
// Nota informativa sobre la simulación
|
||
ImGui::SameLine();
|
||
ImGui::Spacing();
|
||
ImGui::SameLine();
|
||
ImGui::TextDisabled("(educational simulation — real compat requires module flag, TBD)");
|
||
|
||
ImGui::Spacing();
|
||
|
||
// Botón TBD
|
||
ImGui::BeginDisabled(true);
|
||
ImGui::Button("Take screenshots both");
|
||
ImGui::EndDisabled();
|
||
ImGui::SameLine();
|
||
ImGui::TextDisabled("TBD: requires capture API integration");
|
||
|
||
ImGui::Separator();
|
||
|
||
// ---- Labels de columnas ----
|
||
float col_w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.4f, 0.9f, 0.4f, 1.0f));
|
||
ImGui::Text("v2.1.0 — full renderers (current)");
|
||
ImGui::PopStyleColor();
|
||
ImGui::SameLine(col_w + ImGui::GetStyle().ItemSpacing.x);
|
||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.9f, 0.75f, 0.3f, 1.0f));
|
||
ImGui::Text("%s", k_version_labels[g_selected_version]);
|
||
ImGui::PopStyleColor();
|
||
|
||
ImGui::Spacing();
|
||
|
||
// ---- Side-by-side layout ----
|
||
SimVersion sim_ver = static_cast<SimVersion>(g_selected_version);
|
||
float avail_h = ImGui::GetContentRegionAvail().y;
|
||
|
||
if (ImGui::BeginTable("##compat_layout", 2,
|
||
ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchSame)) {
|
||
ImGui::TableSetupColumn("##col_left", ImGuiTableColumnFlags_None, 1.0f);
|
||
ImGui::TableSetupColumn("##col_right", ImGuiTableColumnFlags_None, 1.0f);
|
||
|
||
ImGui::TableNextRow();
|
||
|
||
// ---------- Panel izquierdo: v2.1 full ----------
|
||
ImGui::TableSetColumnIndex(0);
|
||
if (ImGui::BeginChild("##compat_left", ImVec2(-1.0f, avail_h - 4.0f), false)) {
|
||
data_table::TableInput tbl_left = make_base_table("compat_left");
|
||
apply_full_specs(tbl_left);
|
||
|
||
g_left.last_events.clear();
|
||
data_table::render("##compat_left_tbl", { tbl_left }, g_left.dt,
|
||
&g_left.last_events, false);
|
||
qa::consume_events(g_left.last_events);
|
||
}
|
||
ImGui::EndChild();
|
||
|
||
// ---------- Panel derecho: versión degradada ----------
|
||
ImGui::TableSetColumnIndex(1);
|
||
if (ImGui::BeginChild("##compat_right", ImVec2(-1.0f, avail_h - 4.0f), false)) {
|
||
data_table::TableInput tbl_right = make_base_table("compat_right");
|
||
apply_downgraded_specs(tbl_right, sim_ver);
|
||
|
||
g_right.last_events.clear();
|
||
data_table::render("##compat_right_tbl", { tbl_right }, g_right.dt,
|
||
&g_right.last_events, false);
|
||
qa::consume_events(g_right.last_events);
|
||
}
|
||
ImGui::EndChild();
|
||
|
||
ImGui::EndTable();
|
||
}
|
||
}
|
||
|
||
} // namespace tables_qa::tabs
|