From 6560e358bfa59f4c032dd9be64ca15232ab62c74 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Fri, 1 May 2026 00:13:08 +0200 Subject: [PATCH] =?UTF-8?q?feat(main):=20wire=20Inspector=20=E2=80=94=20lo?= =?UTF-8?q?ad=20on=20selection,=20Save/Discard,=20refresh=20caches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue 0008: - types.yaml: stash ParsedTypes en g_app.parsed_types tras parsear (lo consume el Inspector para resolver schemas por type_ref). - load_input: tras load, llama views_inspector_clear_draft + _refresh_caches. - switch_to_project: limpia draft y parsed_types antes de cargar nuevo. - render(): seleccion → load_draft (si single sel y no dirty), Save → entity_update + reload_graph + relocaliza node_idx por sql_id + re-load draft + reselecciona en viewport, Discard → re-load draft. Co-Authored-By: Claude Opus 4.7 (1M context) --- main.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/main.cpp b/main.cpp index c4ea31f..9cd0c4d 100644 --- a/main.cpp +++ b/main.cpp @@ -153,6 +153,8 @@ static bool switch_to_project(const std::string& slug) { // Aplica paths nuevos y abre BDs apply_project_paths(slug); + ge::views_inspector_clear_draft(g_app); + g_app.parsed_types = ge::ParsedTypes{}; if (!ge::layout_store_open(g_layout_db_path.c_str())) { std::fprintf(stderr, "[graph_explorer] layout_store_open failed: %s\n", g_layout_db_path.c_str()); @@ -200,6 +202,8 @@ static bool load_input() { " %zu relations, %zu icons\n", pt.entities.size(), with_schema, total_fields, pt.relations.size(), codepoints.size()); + // Stash en AppState para que el Inspector resuelva schemas (issue 0008). + g_app.parsed_types = std::move(pt); } } @@ -243,6 +247,12 @@ static bool load_input() { ge::views_reset_visibility(g_app); ge::views_apply_visibility(g_app); + // Inspector: refresca caches (tags distintas, lista de tipos) y limpia + // cualquier draft anterior. El draft se cargara cuando el usuario + // seleccione un nodo en el render loop. + ge::views_inspector_clear_draft(g_app); + ge::views_inspector_refresh_caches(g_app); + // --layout inicial (si llego del CLI) int idx = layout_name_to_index(g_layout_initial); if (idx >= 0) { @@ -638,6 +648,68 @@ static void render() { g_app.want_change_type = false; } + // ---- Inspector (issue 0008): sync draft con seleccion + save/discard ---- + { + const auto& sel = g_viewport.selection; + if (sel.size() == 1) { + int sidx = sel.front(); + if (sidx >= 0 && sidx < g_graph.node_count + && sidx != g_app.insp_node_idx + && !g_app.insp_dirty) { + const char* sql_id = ge::entity_index_lookup( + g_idx, g_graph.nodes[sidx].user_data); + ge::views_inspector_load_draft(g_app, sidx, sql_id); + } + } + } + + if (g_app.want_inspector_save && !g_app.insp_entity_id.empty()) { + ge::EntityRecord rec = ge::views_inspector_build_record(g_app); + if (ge::entity_update(g_app.input_db_path.c_str(), rec)) { + std::fprintf(stdout, "[graph_explorer] saved entity %s\n", + rec.id.c_str()); + // Reload del grafo para que cambios de name/type/etc. se reflejen + // en el viewport (label, color del tipo, etc.). + graph::GraphLoadStats stats{}; + if (ge::reload_graph(g_input, &g_graph, &stats)) { + ge::entity_index_build(g_input.uri, &g_idx); + ge::views_reset_visibility(g_app); + ge::views_apply_visibility(g_app); + int restored = ge::layout_store_load(g_graph_hash, g_graph); + (void)restored; + g_atlas_bound = false; + g_gpu_dirty = true; + } + ge::views_inspector_refresh_caches(g_app); + // Re-cargar draft tras el reload (los node_idx pueden haber cambiado + // por reordenamiento de la BD). Buscamos el nuevo idx por sql_id. + int new_idx = -1; + for (int i = 0; i < g_graph.node_count; ++i) { + const char* sid = ge::entity_index_lookup( + g_idx, g_graph.nodes[i].user_data); + if (sid && rec.id == sid) { new_idx = i; break; } + } + if (new_idx >= 0) { + ge::views_inspector_load_draft(g_app, new_idx, rec.id.c_str()); + graph_viewport_clear_selection(g_graph, g_viewport); + graph_viewport_add_to_selection(g_graph, g_viewport, new_idx); + } else { + ge::views_inspector_clear_draft(g_app); + } + } else { + std::fprintf(stderr, "[graph_explorer] entity_update failed for %s\n", + rec.id.c_str()); + } + g_app.want_inspector_save = false; + } + + if (g_app.want_inspector_discard && !g_app.insp_entity_id.empty()) { + int idx = g_app.insp_node_idx; + std::string id = g_app.insp_entity_id; + ge::views_inspector_load_draft(g_app, idx, id.c_str()); + g_app.want_inspector_discard = false; + } + // Reset layout: limpia NF_PINNED en todos los nodos. El layout activo se // reaplica via apply_layout_tick (la toolbar ya lo incrementa). if (g_app.want_unpin_all) {