feat(dashboard): functions explorer + top-level tabs + pie chart fit
- Pie charts (Purity, Kind) ahora reciben plot_h explicito para que respeten el panel contenedor y no desborden cuando la ventana se reduce. - Nueva pestana "Explorer": split layout con lista filtrable a la izquierda (search por nombre/descripcion + combos lang/domain) y panel de detalle a la derecha con tabs Code (read-only multiline), Documentation (selectable text), Tests (con dropdown si la funcion tiene varios tests, muestra lang + file_path + codigo) y Metadata (id, version, file_path, returns, uses_functions, uses_types, params_schema, example, notes). - Reorganizacion de navegacion: TabBar movido arriba, justo debajo de la toolbar. Tabs: Dashboard | Explorer | Projects | Apps | Analysis | Types. Cada tab ocupa toda la zona de contenido. Dashboard incluye KPIs + charts + tabla de Recent Functions. - Cache del Explorer (lista de funciones) invalidado en trigger_reload. - Nuevas funciones HTTP: load_function_detail_http, load_all_functions_http, load_unit_tests_http (todas usan /api/databases/registry/query con escape defensivo de comilla simple en IDs). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+124
@@ -308,6 +308,130 @@ bool load_project_detail_http(const std::string& api_url,
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Function detail endpoints (Explorer)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
bool load_function_detail_http(const std::string& api_url,
|
||||
const std::string& id,
|
||||
FunctionDetail& out) {
|
||||
std::string host; int port;
|
||||
if (!parse_url(api_url, host, port)) return false;
|
||||
|
||||
HttpClient cli(host, port);
|
||||
|
||||
// /api/databases/<db>/query solo acepta { "sql": ... } sin args
|
||||
// parametrizados (ver handleQuery en sqlite_api). Escapamos comilla
|
||||
// simple para que un id con apostrofe no rompa la query — los IDs del
|
||||
// registry son [a-z0-9_]+ asi que el escape es defensivo.
|
||||
std::string escaped;
|
||||
escaped.reserve(id.size());
|
||||
for (char c : id) {
|
||||
if (c == '\'') escaped += "''";
|
||||
else escaped.push_back(c);
|
||||
}
|
||||
std::string sql =
|
||||
"SELECT id, name, lang, domain, kind, purity, version, signature, "
|
||||
"description, code, documentation, notes, example, params_schema, "
|
||||
"uses_functions, uses_types, returns, error_type, file_path, "
|
||||
"created_at, tested FROM functions WHERE id = '" + escaped + "'";
|
||||
|
||||
auto j = api_query(cli, sql.c_str());
|
||||
if (j.is_null() || !j.contains("rows") || j["rows"].empty()) return false;
|
||||
|
||||
auto& row = j["rows"][0];
|
||||
out = FunctionDetail{};
|
||||
out.id = extract_str(row, 0);
|
||||
out.name = extract_str(row, 1);
|
||||
out.lang = extract_str(row, 2);
|
||||
out.domain = extract_str(row, 3);
|
||||
out.kind = extract_str(row, 4);
|
||||
out.purity = extract_str(row, 5);
|
||||
out.version = extract_str(row, 6);
|
||||
out.signature = extract_str(row, 7);
|
||||
out.description = extract_str(row, 8);
|
||||
out.code = extract_str(row, 9);
|
||||
out.documentation = extract_str(row, 10);
|
||||
out.notes = extract_str(row, 11);
|
||||
out.example = extract_str(row, 12);
|
||||
out.params_schema = extract_str(row, 13);
|
||||
out.uses_functions= extract_str(row, 14);
|
||||
out.uses_types = extract_str(row, 15);
|
||||
out.returns = extract_str(row, 16);
|
||||
out.error_type = extract_str(row, 17);
|
||||
out.file_path = extract_str(row, 18);
|
||||
out.created_at = extract_str(row, 19);
|
||||
out.tested = extract_row_int(row, 20) != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_all_functions_http(const std::string& api_url,
|
||||
std::vector<FunctionRow>& out) {
|
||||
std::string host; int port;
|
||||
if (!parse_url(api_url, host, port)) return false;
|
||||
|
||||
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");
|
||||
if (j.is_null() || !j.contains("rows")) return false;
|
||||
|
||||
out.clear();
|
||||
out.reserve(j["rows"].size());
|
||||
for (auto& row : j["rows"]) {
|
||||
FunctionRow r;
|
||||
r.id = extract_str(row, 0);
|
||||
r.name = extract_str(row, 1);
|
||||
r.lang = extract_str(row, 2);
|
||||
r.domain = extract_str(row, 3);
|
||||
r.kind = extract_str(row, 4);
|
||||
r.purity = extract_str(row, 5);
|
||||
r.description = extract_str(row, 6);
|
||||
r.created_at = extract_str(row, 7);
|
||||
r.tested = extract_row_int(row, 8) != 0;
|
||||
out.push_back(std::move(r));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool load_unit_tests_http(const std::string& api_url,
|
||||
const std::string& function_id,
|
||||
std::vector<UnitTestRow>& out) {
|
||||
std::string host; int port;
|
||||
if (!parse_url(api_url, host, port)) return false;
|
||||
|
||||
HttpClient cli(host, port);
|
||||
|
||||
// Mismo escape defensivo que en load_function_detail_http — los IDs son
|
||||
// [a-z0-9_]+ pero por consistencia escapamos comilla simple.
|
||||
std::string escaped;
|
||||
escaped.reserve(function_id.size());
|
||||
for (char c : function_id) {
|
||||
if (c == '\'') escaped += "''";
|
||||
else escaped.push_back(c);
|
||||
}
|
||||
std::string sql =
|
||||
"SELECT id, function_id, name, lang, file_path, code, created_at "
|
||||
"FROM unit_tests WHERE function_id = '" + escaped + "' ORDER BY name";
|
||||
|
||||
auto j = api_query(cli, sql.c_str());
|
||||
if (j.is_null() || !j.contains("rows")) return false;
|
||||
|
||||
out.clear();
|
||||
for (auto& row : j["rows"]) {
|
||||
UnitTestRow r;
|
||||
r.id = extract_str(row, 0);
|
||||
r.function_id = extract_str(row, 1);
|
||||
r.name = extract_str(row, 2);
|
||||
r.lang = extract_str(row, 3);
|
||||
r.file_path = extract_str(row, 4);
|
||||
r.code = extract_str(row, 5);
|
||||
r.created_at = extract_str(row, 6);
|
||||
out.push_back(std::move(r));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mutation endpoints
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user