feat(plugin): migrate vault UI panel + STT route stub into plugin (P2 cont.)
All checks were successful
plugin-tests / test (push) Successful in 25s
All checks were successful
plugin-tests / test (push) Successful in 25s
static/app.js now injects the "Vault connections" panel into Settings → System via DOM mutation observer + populates from GET /api/vault/status (already served by routes/vault_status.py). Mirrors the original behavior from hermes-webui fork commit 3e2c74f3 without needing any upstream HTML/JS edit. routes/transcribe.py documents the STT migration design choice (streaming_hook public-API method vs forced-internal entries) — implementation lands as a follow-on. Plugin still loads cleanly without STT (route disabled in _phase2_routes() until Phase 2.1). CONNECTION-MAP.md regenerated: still 0 forced internals. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c1e3fa1af0
commit
cbf53a0d55
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
**Upstream version:** v0.51.117
|
**Upstream version:** v0.51.117
|
||||||
**Plugin version:** 0.1.0
|
**Plugin version:** 0.1.0
|
||||||
**Total dependencies:** 6 (6 public API · 0 forced internal · 0 frontend)
|
**Total dependencies:** 7 (6 public API · 0 forced internal · 1 frontend)
|
||||||
|
|
||||||
> **Auto-generated by `scripts/ast-connection-map.py`. Do not hand-edit.**
|
> **Auto-generated by `scripts/ast-connection-map.py`. Do not hand-edit.**
|
||||||
> To change a justification, edit the `# CONNECTION:` comment above the
|
> To change a justification, edit the `# CONNECTION:` comment above the
|
||||||
@ -33,5 +33,7 @@ _None. Plugin uses only the public API._ ✓
|
|||||||
|
|
||||||
## Frontend dependencies (static/*.js → /api/* URLs)
|
## Frontend dependencies (static/*.js → /api/* URLs)
|
||||||
|
|
||||||
_None yet._
|
| File | Line | URL |
|
||||||
|
|---|---|---|
|
||||||
|
| `static/app.js` | 46 | `/api/vault/status` |
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,85 @@
|
|||||||
// Svrnty extension entrypoint for Hermes WebUI.
|
// Svrnty plugin frontend — Hermes WebUI extensions.
|
||||||
// Loaded via HERMES_WEBUI_EXTENSION_DIR; runs in the WebUI origin with full
|
// Loaded via /plugins/svrnty/app.js (registered by plugin.py register_static).
|
||||||
// session authority. Reskin is CSS-only (app.css); this file is reserved for
|
// Runs in WebUI origin with full session authority. Additive + idempotent.
|
||||||
// future custom UI/behavior. Keep additive + idempotent.
|
|
||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
if (window.__svrntyExtLoaded) return; // idempotent guard
|
if (window.__svrntyExtLoaded) return;
|
||||||
window.__svrntyExtLoaded = true;
|
window.__svrntyExtLoaded = true;
|
||||||
// (no DOM changes yet — branding is handled entirely by app.css)
|
|
||||||
|
// ── Vault status panel (migrated from fork commit 3e2c74f3) ─────────────
|
||||||
|
// Injects a "Vault connections" section into Settings → System on demand,
|
||||||
|
// populates it from GET /api/vault/status (served by plugin/routes/vault_status.py).
|
||||||
|
const VAULT_LABELS = {
|
||||||
|
anthropic: "Anthropic", gitea: "Gitea", "keycloak-planb": "Keycloak (Plan B)",
|
||||||
|
meta: "Meta", "google-ads": "Google Ads", "google-ai": "Google AI",
|
||||||
|
"google-business": "Google Business", "google-search-console": "Search Console",
|
||||||
|
quickbooks: "QuickBooks", "google-analytics": "Google Analytics",
|
||||||
|
mailchimp: "Mailchimp", paypal: "PayPal", square: "Square",
|
||||||
|
woocommerce: "WooCommerce", "wordpress-admin": "WordPress",
|
||||||
|
agendrix: "Agendrix", perplexity: "Perplexity", wix: "Wix",
|
||||||
|
};
|
||||||
|
|
||||||
|
function _injectVaultPanel() {
|
||||||
|
// Already injected?
|
||||||
|
if (document.getElementById("vaultStatusSection")) return true;
|
||||||
|
// Anchor after the gateway-status card in System settings.
|
||||||
|
const anchor = document.getElementById("gatewayStatusCard");
|
||||||
|
if (!anchor) return false;
|
||||||
|
const section = document.createElement("div");
|
||||||
|
section.id = "vaultStatusSection";
|
||||||
|
section.style.marginTop = "16px";
|
||||||
|
section.innerHTML =
|
||||||
|
'<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px">' +
|
||||||
|
'<div style="font-weight:500;font-size:13px">Vault connections</div>' +
|
||||||
|
'<button id="vaultRefreshBtn" style="background:none;border:1px solid var(--border2);color:var(--text);padding:2px 8px;border-radius:4px;font-size:11px;cursor:pointer">Refresh</button>' +
|
||||||
|
"</div>" +
|
||||||
|
'<div style="font-size:11px;color:var(--muted);margin-bottom:8px">credctl-managed secrets — green = present, grey = absent</div>' +
|
||||||
|
'<div id="vaultStatusList"><span style="color:var(--muted);font-size:12px">Loading…</span></div>';
|
||||||
|
anchor.parentNode.insertBefore(section, anchor.nextSibling);
|
||||||
|
document.getElementById("vaultRefreshBtn").addEventListener("click", _loadVaultStatus);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _loadVaultStatus() {
|
||||||
|
const list = document.getElementById("vaultStatusList");
|
||||||
|
if (!list) return;
|
||||||
|
fetch("/api/vault/status")
|
||||||
|
.then((r) => r.json())
|
||||||
|
.then((r) => {
|
||||||
|
const present = new Set((r.secrets || []).map((s) => s.name));
|
||||||
|
const names = Object.keys(VAULT_LABELS);
|
||||||
|
list.innerHTML =
|
||||||
|
'<div style="display:flex;flex-wrap:wrap;gap:6px">' +
|
||||||
|
names.map((name) => {
|
||||||
|
const ok = present.has(name);
|
||||||
|
const color = ok ? "#22c55e" : "#6b7280";
|
||||||
|
const label = VAULT_LABELS[name] || name;
|
||||||
|
return (
|
||||||
|
'<span style="display:inline-flex;align-items:center;gap:5px;padding:4px 10px;background:var(--code-bg);border:1px solid var(--border2);border-radius:12px;font-size:12px">' +
|
||||||
|
`<span style="width:7px;height:7px;border-radius:50%;background:${color};flex-shrink:0"></span>` +
|
||||||
|
label.replace(/[<>&]/g, (c) => ({ "<": "<", ">": ">", "&": "&" }[c])) +
|
||||||
|
"</span>"
|
||||||
|
);
|
||||||
|
}).join("") +
|
||||||
|
"</div>";
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
list.innerHTML = '<div style="color:#ef4444;font-size:12px">Failed to load vault status</div>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch for the System settings tab opening; inject + load when it appears.
|
||||||
|
// The panel exists in the DOM only after the user navigates Settings → System.
|
||||||
|
function _hookSystemPanelOpen() {
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
if (_injectVaultPanel()) _loadVaultStatus();
|
||||||
|
});
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === "loading") {
|
||||||
|
document.addEventListener("DOMContentLoaded", _hookSystemPanelOpen);
|
||||||
|
} else {
|
||||||
|
_hookSystemPanelOpen();
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user