// 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 #include #include 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(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