Files
fn_registry/dev/issues/0071-extract-reusable-cpp-panels-roadmap.md
T
egutierrez f3c0a5c532 docs(issues): add 0071 cpp panels roadmap + 0071f subprocess_streamer
0071 cataloga paneles ImGui candidatos a extraccion por tier (rule of three).
0071f es el primer sub-issue activable: subprocess_streamer ya tiene 3 consumidores
reales en graph_explorer (chat, jobs, extract_panel). README actualizado con 0068-0071+0071f.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 01:26:42 +02:00

10 KiB

id, title, status, priority, created, related_apps, related_issues_app
id title status priority created related_apps related_issues_app
0071 Extraer paneles ImGui reutilizables de las apps C++ a cpp/functions/ — roadmap pending medium 2026-05-09
graph_explorer
registry_dashboard
odr_console
navegator_dashboard
navegator/0001

Contexto

Las apps C++ del registry (cpp/apps/*, projects/*/apps/*) llevan acumulando paneles ImGui que comparten patron pero viven dentro de cada app. Hay duplicacion observable y mas que va a aparecer (navegator_dashboard quiere chat panel igual que graph_explorer; el dashboard de Tabs va a parecerse al panel "Browsers").

Hoy ya estan en el registro cpp/functions/core/: dashboard_panel, fullscreen_window, log_window, modal_dialog, tree_view, selectable_text. La capa visual (tokens, theming, iconos, settings/about/menubar) vive en fn_framework. Esto cubre primitivas. Falta una tier intermedia: paneles compuestos (mas grandes que un widget, mas pequeños que una app).

Este issue documenta el roadmap de que extraer, cuando, y por que.

Principios

  1. Rule of three — no extraer hasta que haya 2-3 consumidores reales. Pre-extraer crea abstracciones malas.
  2. Consumidor primero — escribir el panel inline en la app. Si una segunda app lo necesita, copiar+adaptar. Si una tercera lo pide, extraer.
  3. Parametrizable, no monolitico — los paneles extraidos reciben un struct de config (callbacks, paths, env vars) en vez de hardcodear nombres.
  4. No exponer estado global del modulo extraido — usar contexto opaco que cada app crea/destruye.

Catalogo: paneles candidatos detectados

Revisado todas las apps C++ vivas. Por cada panel: lineas, consumidores actuales, consumidores potenciales, decision.

Tier 0 — ya extraidos ✓

Panel Ubicacion
dashboard cards grid cpp/functions/core/dashboard_panel.{h,cpp}
fullscreen window wrapper cpp/functions/core/fullscreen_window.{h,cpp}
log window con buffer cpp/functions/core/log_window.{h,cpp}
modal dialog cpp/functions/core/modal_dialog.{h,cpp}
tree view cpp/functions/core/tree_view.{h,cpp}
selectable text cpp/functions/core/selectable_text.{h,cpp}

Estos definen el "lower-tier" — primitivas. Los nuevos extracts componen sobre estos.

Tier 1 — extraer cuando aparezca el 3er consumidor

1.1 claude_chat_panel (origen: graph_explorer/chat.cpp, 1241 LoC)

Que es: panel ImGui que arranca un subprocess claude -p, le envia mensajes del usuario, parsea stream-json, renderiza historial con tool-use detectado, expone callbacks para que la app recargue cuando el agente muta su BD.

Consumidores hoy: graph_explorer.

Consumidores potenciales:

  • navegator_dashboard (issue navegator/0001) — chat para controlar Chrome.
  • kanban (futuro) — agente para crear/mover cards.
  • registry_dashboard — agente para crear functions/proposals.

Por que tier 1 (no tier 0):

  • 59 referencias a gx-cli, GX_OPS_DB, GX_APP_DB, agent_mutations. Acoplamiento alto a graph_explorer.
  • Refactor a config parametrizado es ~4-6h y modifica codigo que YA funciona — riesgo regresion.
  • Con solo 2 consumidores no hay claridad de que parametrizar.

Cuando extraer: 3er consumidor pide chat. Hasta entonces: copiar+adaptar (graph_explorer mantiene el suyo, navegator copia el suyo).

API propuesta cuando se extraiga:

struct ClaudeChatConfig {
    const char* claude_bin;             // "claude" o WSL path
    const char* cli_tool_name;          // "gx-cli", "cdp-cli", "kanban-cli", ...
    const char* cli_tool_dir;
    std::map<std::string, std::string> env_vars;  // GX_*, NAVD_*, ...
    const char* mcp_config_path;        // o func que lo genera on-demand
    const char* system_prompt;          // opcional
    std::function<int()> mutations_counter;  // app-side reload trigger
    const char* log_file_path;
};

namespace fn_ui {
    struct ChatHandle;  // opaco
    ChatHandle* chat_create(const ClaudeChatConfig& cfg);
    void chat_send(ChatHandle*, const char* user_text);
    void chat_render(ChatHandle*, bool* p_open);
    void chat_destroy(ChatHandle*);
}

1.2 jobs_queue_panel (origen: graph_explorer/jobs.cpp + odr_console/jobs)

Que es: panel + sistema de jobs asincronos. Lista jobs en cola/running/done con barra de progreso, stdout/stderr capture, cancelable, persistente entre sesiones.

Consumidores hoy: graph_explorer (jobs.cpp + views_jobs.cpp), odr_console (panel Jobs).

Consumidores potenciales:

  • navegator_dashboard — scraping jobs (un crawl es un job).
  • registry_dashboard — fn index, fn run jobs.

Por que tier 1: ya hay 2 consumidores, parece duplicacion clara. Inspeccionar diff entre ambos antes de extraer — pueden estar implementados distinto y no reusarse del todo.

Cuando extraer: despues de auditar que graph_explorer/jobs.cpp y odr_console/jobs comparten >70% del codigo. Si si: 3er consumidor (navegator scraping) detona la extraccion.

API propuesta:

namespace fn_ui {
    struct Job {
        std::string id;
        std::string title;
        std::function<int(JobContext&)> run;  // retorna exit code
        // ...
    };
    void jobs_panel_init(const char* persistence_db_path);
    void jobs_panel_submit(const Job&);
    void jobs_panel_render(bool* p_open);
}

Tier 2 — extraer cuando aparezca el 2do consumidor (todavia no detectado)

2.1 project_switcher_panel (origen: graph_explorer/project_manager.cpp)

Que es: sidebar/menu para cambiar entre subcarpetas de proyectos (cada proyecto tiene su DB y settings). Persiste el ultimo proyecto abierto.

Hoy en: graph_explorer.

Potencial: navegator_dashboard (perfiles browser como proyectos), registry_dashboard (apps como proyectos), kanban (boards).

Cuando extraer: cuando navegator_dashboard quiera multi-perfil persistente con settings por perfil. v3 del dashboard probablemente.

2.2 key_value_inspector_panel (origen: graph_explorer/views.cpp Inspector)

Que es: panel "Inspector" generico que muestra propiedades de un objeto seleccionado en formato key:value, con edicion inline opcional. Hoy es ad-hoc para entities.

Potencial: navegator_dashboard (Tab Detail mostrar propiedades de pestaña), registry_dashboard (function detail), kanban (card details).

Cuando extraer: cuando dos paneles de "ver propiedades de cosa seleccionada" tengan codigo casi identico.

2.3 paste_and_extract_panel (origen: graph_explorer/extract_panel.cpp)

Que es: panel que recibe texto pegado, invoca enricher Python, muestra entities extraidas + boton para insertarlas.

Potencial: navegator_dashboard (extraer texto seleccionado de pestaña), registry_dashboard (extraer descripcion para auto-fill function metadata).

Cuando extraer: 2do consumidor con flujo similar.

2.4 http_request_inspector_panel (origen: registry_dashboard/http_client.cpp + futuro navegator_dashboard/network)

Que es: panel para ver una peticion HTTP (request line, headers, body) renderizado bonito. Read-only.

Potencial: navegator_dashboard (Network panel renderiza HAR entries), registry_dashboard (mostrar requests outgoing del fn_registry_api).

Cuando extraer: cuando 0070b (HAR record) sea consumido por algo que quiera renderizarlo bien.

Tier 3 — NO extraer (especificos de su app)

Panel Por que NO
graph_explorer/types_registry Acoplado a types.yaml schema especifico.
graph_explorer/node_groups DuckDB + grafo + tipo "Table" del schema graph_explorer.
graph_explorer/layout_store Posiciones de nodos del grafo, schema especifico.
graph_explorer/views.cpp::Legend Mapa de tipos→colores especifico del grafo.
graph_explorer/views.cpp::Stats Conteos por tipo de entity, schema especifico.
navegator_dashboard/browsers panel Detector chrome.exe Win32, hereda WMI/CIM, especifico Windows.
odr_console/datasets panel Listado especifico del flujo ODR.

Estos viven en su app. Si emerge un patron despues, se reconsidera.

Tier 4 — primitivas que sirven a TODOS los paneles (extraccion oportunista, sin app-driver)

Util tener antes de los Tier 1-2 para hacer la extraccion mas limpia:

Primitiva Para que
subprocess_streamer.{h,cpp} Encapsula spawn + pipes + read-thread + queue. Lo usaria chat_panel + jobs_panel.
mcp_config_writer.{h,cpp} Genera .mcp.json para Claude. Lo usaria chat_panel.
app_db_init.{h,cpp} Patron generico de "abrir SQLite junto al exe + aplicar migrations embed.FS". Hoy cada app reimplementa.
key_input_history.{h,cpp} Input + flecha arriba/abajo recupera entradas previas. Util en chat + REPL evaluate.
json_log_renderer.{h,cpp} Render de stream JSON estilo claude-code (rol, tool_use, contenido). Util tanto en chat de graph_explorer como en futuros chats.

Estas primitivas se extraen cuando empieza la extraccion de un Tier 1 que las necesita (no antes — caen en el "rule of three" tambien).

Estrategia de adopcion

Por demanda:

  1. Hoy (tras este issue): copiar+adaptar chat.cpp a navegator_dashboard. Documentar la duplicacion. NO extraer.
  2. Cuando aparezca 3er consumidor de chat (o jobs, o project_switcher): pausar feature work, refactorizar el extract con vista 3D.
  3. Auditoria periodica trimestral: cada 3 meses revisar este issue, contar consumidores actuales, decidir si activar extracts.

Sub-issues iniciales (no abrir hasta tener 3er consumidor identificado)

  • 0071a — extract claude_chat_panel (cuando 3 apps lo pidan).
  • 0071b — extract jobs_queue_panel (auditar duplicacion graph_explorer/odr_console primero).
  • 0071c — extract project_switcher_panel.
  • 0071d — extract key_value_inspector_panel.
  • 0071e — extract http_request_inspector_panel.

Definicion de hecho (issue 0071 cerrado)

  • Catalogo arriba esta vivo, refleja apps actuales.
  • Auditoria trimestral mantiene la lista actualizada.
  • Sub-issues 0071a-e: cada uno abre cuando se cumple su criterio.
  • Cuando todos los Tier 1 + 2 esten extraidos, este issue se marca completed.

Anti-patron a evitar

  • Big-bang refactor: extraer 5 paneles a la vez, con interfaces no validadas, rompiendo todas las apps. NO.
  • Pre-extraer "por si acaso": el panel mas dificil es el que solo tiene 1 consumidor — no sabes que parametrizar. NO.
  • Library wrapper sin control: meter claude_chat_panel con 30 hooks/callbacks "para flexibilidad". KISS — solo expone lo que el 3er consumidor demuestra que necesita.