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) {