chore: auto-commit (4 archivos)

- data.h
- data_http.cpp
- views.cpp
- appicon.ico

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 16:33:25 +02:00
parent 9cbf2f7492
commit 04cfa2aba0
4 changed files with 136 additions and 3 deletions
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+4
View File
@@ -46,6 +46,10 @@ struct FunctionRow {
std::string description;
std::string created_at;
bool tested = false;
// JSON array string ("[\"a\",\"b\"]") con IDs de funciones consumidas.
// Se carga junto con la lista para soportar reverse lookup "Used by" en
// el tab Dependencies del Explorer sin endpoint extra.
std::string uses_functions;
};
struct AppRow {
+2 -1
View File
@@ -373,7 +373,7 @@ bool load_all_functions_http(const std::string& api_url,
HttpClient cli(host, port);
auto j = api_query(cli,
"SELECT id, name, lang, domain, kind, purity, description, "
"created_at, tested FROM functions ORDER BY name");
"created_at, tested, uses_functions FROM functions ORDER BY name");
if (j.is_null() || !j.contains("rows")) return false;
out.clear();
@@ -389,6 +389,7 @@ bool load_all_functions_http(const std::string& api_url,
r.description = extract_str(row, 6);
r.created_at = extract_str(row, 7);
r.tested = extract_row_int(row, 8) != 0;
r.uses_functions = extract_str(row, 9);
out.push_back(std::move(r));
}
return true;
+130 -2
View File
@@ -325,6 +325,31 @@ static int g_explorer_test_idx = 0;
static char g_explorer_filter[128] = {};
static int g_explorer_lang_idx = 0;
static int g_explorer_domain_idx = 0;
// Caches del tab Dependencies — se recomputan en explorer_select() para no
// reparsar JSON cada frame. uses_funcs/uses_types: parse de d.uses_functions
// y d.uses_types. used_by: reverse lookup cliente-side sobre g_explorer_funcs.
static std::vector<std::string> g_explorer_uses_funcs;
static std::vector<std::string> g_explorer_uses_types;
static std::vector<std::string> g_explorer_used_by;
// Parser tolerante de arrays JSON de strings (`["a","b"]`). Las entradas de
// la BD son IDs `[a-z0-9_]+` sin escapes, asi que un walker simple basta y
// evita anadir dependencia a nlohmann/json (que vive solo en data_http.cpp).
static std::vector<std::string> parse_string_array_json(const std::string& json_str) {
std::vector<std::string> out;
if (json_str.empty() || json_str == "[]") return out;
size_t i = 0, n = json_str.size();
while (i < n) {
while (i < n && json_str[i] != '"') i++;
if (i >= n) break;
i++; // past opening "
size_t start = i;
while (i < n && json_str[i] != '"') i++;
if (i > start) out.emplace_back(json_str.substr(start, i - start));
if (i < n) i++; // past closing "
}
return out;
}
static void trigger_reload() {
ImGui::GetIO().UserData = reinterpret_cast<void*>(1);
@@ -1378,9 +1403,22 @@ static void explorer_select(const std::string& id) {
g_explorer_detail = FunctionDetail{};
g_explorer_tests.clear();
g_explorer_test_idx = 0;
g_explorer_uses_funcs.clear();
g_explorer_uses_types.clear();
g_explorer_used_by.clear();
if (!g_api_url.empty() && !id.empty()) {
load_function_detail_http(g_api_url, id, g_explorer_detail);
load_unit_tests_http(g_api_url, id, g_explorer_tests);
// Caches del tab Dependencies — forward + reverse.
g_explorer_uses_funcs = parse_string_array_json(g_explorer_detail.uses_functions);
g_explorer_uses_types = parse_string_array_json(g_explorer_detail.uses_types);
for (const auto& f : g_explorer_funcs) {
if (f.id == id) continue;
auto deps = parse_string_array_json(f.uses_functions);
for (const auto& dep : deps) {
if (dep == id) { g_explorer_used_by.push_back(f.id); break; }
}
}
}
}
@@ -1574,6 +1612,97 @@ void draw_functions_explorer() {
}
ImGui::EndTabItem();
}
// Tab Dependencies: muestra uses_functions, uses_types, y reverse
// lookup "used by" (clientes-side sobre g_explorer_funcs). Caches
// (g_explorer_uses_*) se rellenan en explorer_select().
int total_deps = (int)(g_explorer_uses_funcs.size()
+ g_explorer_uses_types.size());
char deps_label[32];
std::snprintf(deps_label, sizeof(deps_label),
"Dependencies (%d)", total_deps);
if (ImGui::BeginTabItem(deps_label)) {
ImGui::BeginChild("##deps_scroll", ImVec2(0, 0));
// Section 1: Uses functions (clickables; color dim si la id
// no resuelve en el catalogo actual).
char hdr1[64];
std::snprintf(hdr1, sizeof(hdr1),
"Uses functions (%zu)",
g_explorer_uses_funcs.size());
if (ImGui::CollapsingHeader(hdr1,
ImGuiTreeNodeFlags_DefaultOpen)) {
if (g_explorer_uses_funcs.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text,
fn_tokens::colors::text_dim);
ImGui::TextUnformatted("(none)");
ImGui::PopStyleColor();
} else {
for (const auto& fid : g_explorer_uses_funcs) {
bool resolves = false;
for (const auto& f : g_explorer_funcs) {
if (f.id == fid) { resolves = true; break; }
}
ImVec4 col = resolves
? fn_tokens::colors::text
: fn_tokens::colors::text_dim;
ImGui::PushStyleColor(ImGuiCol_Text, col);
ImGui::PushID(fid.c_str());
if (ImGui::Selectable(fid.c_str())) {
if (resolves) explorer_select(fid);
}
ImGui::PopID();
ImGui::PopStyleColor();
}
}
}
// Section 2: Uses types — sin navegacion (no hay type explorer
// todavia); bullets para indicar listado pasivo.
char hdr2[64];
std::snprintf(hdr2, sizeof(hdr2),
"Uses types (%zu)",
g_explorer_uses_types.size());
if (ImGui::CollapsingHeader(hdr2,
ImGuiTreeNodeFlags_DefaultOpen)) {
if (g_explorer_uses_types.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text,
fn_tokens::colors::text_dim);
ImGui::TextUnformatted("(none)");
ImGui::PopStyleColor();
} else {
for (const auto& tid : g_explorer_uses_types) {
ImGui::BulletText("%s", tid.c_str());
}
}
}
// Section 3: Used by (reverse) — clientes detectados al
// seleccionar la funcion.
char hdr3[64];
std::snprintf(hdr3, sizeof(hdr3),
"Used by (%zu)",
g_explorer_used_by.size());
if (ImGui::CollapsingHeader(hdr3,
ImGuiTreeNodeFlags_DefaultOpen)) {
if (g_explorer_used_by.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text,
fn_tokens::colors::text_dim);
ImGui::TextUnformatted("(no consumers in catalog)");
ImGui::PopStyleColor();
} else {
for (const auto& fid : g_explorer_used_by) {
ImGui::PushID(fid.c_str());
if (ImGui::Selectable(fid.c_str())) {
explorer_select(fid);
}
ImGui::PopID();
}
}
}
ImGui::EndChild();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Metadata")) {
ImGui::BeginChild("##meta_scroll", ImVec2(0, 0));
auto kv = [](const char* k, const std::string& v) {
@@ -1590,8 +1719,7 @@ void draw_functions_explorer() {
kv("Created:", d.created_at);
kv("Returns:", d.returns);
kv("Error type:", d.error_type);
kv("Uses functions:", d.uses_functions);
kv("Uses types:", d.uses_types);
// Uses functions/types se muestran en el tab Dependencies.
kv("Params schema:", d.params_schema);
kv("Example:", d.example);
kv("Notes:", d.notes);