feat(views): Inspector editable — identidad, fields tipados, extras, tags

Issue 0008 — refactor del panel Inspector de read-only a editable.

views.h:
- AppState gana ParsedTypes parsed_types (schema vivo del proyecto), draft
  del Inspector (insp_*: name/type/desc/status buffers, field_keys/values
  paralelas, is_extra mask, tags vector, dirty flag), y dos triggers
  (want_inspector_save, want_inspector_discard).
- Helpers expuestos: views_inspector_clear_draft, _refresh_caches,
  _load_draft, _build_record.

views.cpp:
- views_inspector_load_draft: entity_load_full → buffers; campos del
  schema primero (orden del EntitySpec), extras detras.
- views_inspector_build_record: reconstruye EntityRecord respetando el
  schema para decidir is_string de cada campo (FK_BOOL → 'true'/'false',
  FK_INT/FLOAT → literal, resto → string). Extras siempre string.
- views_inspector: render por bloques:
  * Identity: name, type combo (lista del proyecto + tipos del grafo),
    status combo, description multiline.
  * Fields del schema: render por kind (string→InputText con hint,
    int→InputInt, float→InputDouble, bool→Checkbox, date→InputText
    con hint YYYY-MM-DD, url→InputText + boton Open en navegador,
    enum→Combo con values). Required marcado con '*'.
  * Extras: lista key-value con boton trash por fila + 'Add' al final.
  * Tags: chips clickables (click = quitar) + input con autocomplete
    (lista compacta de tags distintas en BD).
  * Footer: Save/Discard/Open notes + label '(modified)' si dirty.
  * Neighbors read-only (igual que antes).
- Si el draft no esta sincronizado con la seleccion actual y NO hay
  cambios pendientes, el inspector muestra 'Cargando...' (main.cpp
  carga). Si hay dirty, banner 'Save/Discard primero' bloqueando.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 00:13:01 +02:00
parent 6ed00fcdce
commit b2ae793727
2 changed files with 591 additions and 15 deletions
+60
View File
@@ -3,6 +3,9 @@
#include <string>
#include <vector>
#include "types_registry.h"
#include "entity_ops.h"
struct GraphData;
struct GraphViewportState;
@@ -96,6 +99,43 @@ struct AppState {
bool want_save_note = false;
bool want_open_note = false; // doble click → cargar y abrir
int open_note_target = -1; // node_idx a abrir
// ---- Inspector editable (issue 0008) ----------------------------------
// Schema vivo del proyecto activo (load/save desde types.yaml).
ParsedTypes parsed_types;
// Draft del inspector — todo lo que el usuario esta editando para el
// nodo seleccionado. Se carga desde BD al cambiar la seleccion (si no
// hay cambios pendientes) y se persiste con entity_update al guardar.
int insp_node_idx = -1;
std::string insp_entity_id;
char insp_name_buf[256] = {};
char insp_type_buf[64] = {};
std::vector<char> insp_desc_buf; // multiline
int insp_status_idx = 0; // 0=active 1=stale 2=corrupted 3=archived
// Listas paralelas: keys + valores actuales de los campos de metadata.
// Las claves del schema del tipo van primero (en su orden), las "extras"
// van detras. `is_extra[i]` distingue para render diferenciado y para
// permitir borrar solo extras desde la UI.
std::vector<std::string> insp_field_keys;
std::vector<std::string> insp_field_values;
std::vector<unsigned char> insp_is_extra;
std::vector<std::string> insp_tags;
char insp_tag_input[64] = {};
char insp_extra_key[64] = {};
bool insp_dirty = false;
bool insp_show_unsaved = false;
int insp_pending_target = -1;
bool want_inspector_save = false;
bool want_inspector_discard = false;
// Caches refrescadas tras cargar grafo o tras Save.
std::vector<std::string> insp_tag_suggestions;
std::vector<std::string> insp_type_options;
};
// Toolbar superior (Open file, Layout selector, Filters..., Fit, Save layout).
@@ -133,4 +173,24 @@ void views_apply_visibility(AppState& app);
// los tipos del grafo activo. Llamar tras cargar/recargar el grafo.
void views_reset_visibility(AppState& app);
// ---- Inspector editable helpers (issue 0008) ------------------------------
// Refresca insp_tag_suggestions e insp_type_options leyendo BD y schema.
// Llamar tras cargar el grafo o tras un Save.
void views_inspector_refresh_caches(AppState& app);
// Carga el draft del Inspector desde la BD para el nodo `node_idx`. Si el
// nodo no es resoluble o no existe, deja el draft vacio. No respeta dirty:
// el caller debe haberlo manejado ya.
void views_inspector_load_draft(AppState& app, int node_idx,
const char* entity_id);
// Construye un EntityRecord desde el draft actual respetando el schema
// del type_ref para decidir is_string de cada metadata field.
EntityRecord views_inspector_build_record(const AppState& app);
// Resetea el draft (todos los buffers + dirty=false). Util tras Save o
// al cambiar de proyecto.
void views_inspector_clear_draft(AppState& app);
} // namespace ge