mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 00:40:45 +08:00
Localize Plugins actions and parallelize Plugins/Skills boot fetches.
Cut time-to-interactive on those admin pages and align button/table copy with the existing zh/en i18n switch. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
f6f129931f
commit
f92cb85a4a
6 changed files with 141 additions and 84 deletions
|
|
@ -5,9 +5,9 @@
|
|||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>oliver</title>
|
||||
<!-- Avoid render-blocking external fonts (can stall first paint ~30s on blocked networks). -->
|
||||
<link rel="stylesheet" href="/admin/assets/styles.css?v=20260812-17" />
|
||||
<link rel="stylesheet" href="/admin/assets/theme-deepseek.css?v=20260812-17" />
|
||||
<link rel="stylesheet" href="/admin/assets/theme-presets.css?v=20260812-17" />
|
||||
<link rel="stylesheet" href="/admin/assets/styles.css?v=20260812-18" />
|
||||
<link rel="stylesheet" href="/admin/assets/theme-deepseek.css?v=20260812-18" />
|
||||
<link rel="stylesheet" href="/admin/assets/theme-presets.css?v=20260812-18" />
|
||||
<style>
|
||||
/* First paint before app.js runs: keep admin from showing a blank dark screen. */
|
||||
.admin-boot-splash {
|
||||
|
|
@ -129,33 +129,33 @@
|
|||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"/admin/assets/app.js": "/admin/assets/app.js?v=20260812-17",
|
||||
"/admin/assets/js/asset-v.js": "/admin/assets/js/asset-v.js?v=20260812-17",
|
||||
"/admin/assets/js/core.js": "/admin/assets/js/core.js?v=20260812-17",
|
||||
"/admin/assets/js/i18n/index.js": "/admin/assets/js/i18n/index.js?v=20260812-17",
|
||||
"/admin/assets/js/i18n/messages-en.js": "/admin/assets/js/i18n/messages-en.js?v=20260812-17",
|
||||
"/admin/assets/js/i18n/messages-zh.js": "/admin/assets/js/i18n/messages-zh.js?v=20260812-17",
|
||||
"/admin/assets/js/main.js": "/admin/assets/js/main.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/attachments.js": "/admin/assets/js/pages/attachments.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/audit.js": "/admin/assets/js/pages/audit.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/authz.js": "/admin/assets/js/pages/authz.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/legacy-admin.js": "/admin/assets/js/pages/legacy-admin.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/legacy.js": "/admin/assets/js/pages/legacy.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/login.js": "/admin/assets/js/pages/login.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/memory.js": "/admin/assets/js/pages/memory.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/models.js": "/admin/assets/js/pages/models.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/plugins.js": "/admin/assets/js/pages/plugins.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/profile.js": "/admin/assets/js/pages/profile.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/scheduled-jobs.js": "/admin/assets/js/pages/scheduled-jobs.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/skills.js": "/admin/assets/js/pages/skills.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/stack.js": "/admin/assets/js/pages/stack.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/users.js": "/admin/assets/js/pages/users.js?v=20260812-17",
|
||||
"/admin/assets/js/pages/workspace-paths.js": "/admin/assets/js/pages/workspace-paths.js?v=20260812-17",
|
||||
"/admin/assets/js/router.js": "/admin/assets/js/router.js?v=20260812-17",
|
||||
"/admin/assets/js/state.js": "/admin/assets/js/state.js?v=20260812-17"
|
||||
"/admin/assets/app.js": "/admin/assets/app.js?v=20260812-18",
|
||||
"/admin/assets/js/asset-v.js": "/admin/assets/js/asset-v.js?v=20260812-18",
|
||||
"/admin/assets/js/core.js": "/admin/assets/js/core.js?v=20260812-18",
|
||||
"/admin/assets/js/i18n/index.js": "/admin/assets/js/i18n/index.js?v=20260812-18",
|
||||
"/admin/assets/js/i18n/messages-en.js": "/admin/assets/js/i18n/messages-en.js?v=20260812-18",
|
||||
"/admin/assets/js/i18n/messages-zh.js": "/admin/assets/js/i18n/messages-zh.js?v=20260812-18",
|
||||
"/admin/assets/js/main.js": "/admin/assets/js/main.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/attachments.js": "/admin/assets/js/pages/attachments.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/audit.js": "/admin/assets/js/pages/audit.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/authz.js": "/admin/assets/js/pages/authz.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/legacy-admin.js": "/admin/assets/js/pages/legacy-admin.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/legacy.js": "/admin/assets/js/pages/legacy.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/login.js": "/admin/assets/js/pages/login.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/memory.js": "/admin/assets/js/pages/memory.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/models.js": "/admin/assets/js/pages/models.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/plugins.js": "/admin/assets/js/pages/plugins.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/profile.js": "/admin/assets/js/pages/profile.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/scheduled-jobs.js": "/admin/assets/js/pages/scheduled-jobs.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/skills.js": "/admin/assets/js/pages/skills.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/stack.js": "/admin/assets/js/pages/stack.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/users.js": "/admin/assets/js/pages/users.js?v=20260812-18",
|
||||
"/admin/assets/js/pages/workspace-paths.js": "/admin/assets/js/pages/workspace-paths.js?v=20260812-18",
|
||||
"/admin/assets/js/router.js": "/admin/assets/js/router.js?v=20260812-18",
|
||||
"/admin/assets/js/state.js": "/admin/assets/js/state.js?v=20260812-18"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="module" src="/admin/assets/app.js?v=20260812-17" onerror="(function(){var lang='zh';try{lang=String(localStorage.getItem('ops_admin_lang')||'zh').toLowerCase();}catch(e){}if(lang!=='en')lang='zh';var msg=lang==='en'?{t:'Failed to load admin scripts',h:'Confirm /admin/assets/app.js and /admin/assets/js/ are reachable.'}:{t:'无法加载管理台脚本',h:'请确认 /admin/assets/app.js 与 /admin/assets/js/ 可访问。'};var s=document.getElementById('admin-boot-splash');if(s){var a=s.querySelector('.admin-boot-splash__title span:last-child');var b=s.querySelector('.admin-boot-splash__muted');if(a)a.textContent=msg.t;if(b)b.textContent=msg.h;}})()"></script>
|
||||
<script type="module" src="/admin/assets/app.js?v=20260812-18" onerror="(function(){var lang='zh';try{lang=String(localStorage.getItem('ops_admin_lang')||'zh').toLowerCase();}catch(e){}if(lang!=='en')lang='zh';var msg=lang==='en'?{t:'Failed to load admin scripts',h:'Confirm /admin/assets/app.js and /admin/assets/js/ are reachable.'}:{t:'无法加载管理台脚本',h:'请确认 /admin/assets/app.js 与 /admin/assets/js/ 可访问。'};var s=document.getElementById('admin-boot-splash');if(s){var a=s.querySelector('.admin-boot-splash__title span:last-child');var b=s.querySelector('.admin-boot-splash__muted');if(a)a.textContent=msg.t;if(b)b.textContent=msg.h;}})()"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@
|
|||
* - interfaces/admin/static/index.html importmap + CSS/JS ?v=
|
||||
* - interfaces/admin/static/app.js entry query (optional if importmap covers it)
|
||||
*/
|
||||
export const ADMIN_ASSET_V = "20260812-17";
|
||||
export const ADMIN_ASSET_V = "20260812-18";
|
||||
|
|
|
|||
|
|
@ -276,6 +276,38 @@ export default {
|
|||
"plugins.toc.install": "Install",
|
||||
"plugins.toc.instances": "Instances",
|
||||
"plugins.toc.policy": "Policy",
|
||||
"plugins.action.cancel": "Cancel",
|
||||
"plugins.action.clear": "Clear",
|
||||
"plugins.action.delete": "Delete",
|
||||
"plugins.action.disable": "Disable",
|
||||
"plugins.action.edit": "Edit",
|
||||
"plugins.action.enable": "Enable",
|
||||
"plugins.action.exportJson": "Export JSON",
|
||||
"plugins.action.exportJsonTitle": "Download Cursor mcpServers snapshot for reinstall / migration",
|
||||
"plugins.action.health": "Health",
|
||||
"plugins.action.install": "Install",
|
||||
"plugins.action.locate": "Locate",
|
||||
"plugins.action.save": "Save",
|
||||
"plugins.action.saveBinding": "Save Binding",
|
||||
"plugins.action.saveToolPolicy": "Save Tool Policy",
|
||||
"plugins.action.selectAll": "Select All",
|
||||
"plugins.action.syncTools": "Sync Tools",
|
||||
"plugins.binding.empty": "No MCP servers installed yet.",
|
||||
"plugins.binding.hint": "Bind MCP servers to specialists (many-to-many).",
|
||||
"plugins.binding.reverse": "Reverse view: server -> specialists",
|
||||
"plugins.binding.specialist": "Specialist",
|
||||
"plugins.col.action": "action",
|
||||
"plugins.col.boundSpecialists": "bound specialists",
|
||||
"plugins.col.commandUrl": "command / url",
|
||||
"plugins.col.enabled": "enabled",
|
||||
"plugins.col.health": "health",
|
||||
"plugins.col.serverId": "server_id",
|
||||
"plugins.col.tools": "tools",
|
||||
"plugins.confirm.delete": "Delete {sid} from MCP registry?",
|
||||
"plugins.edit.configHint": "Cursor server config (single mcpServers value)",
|
||||
"plugins.edit.enabled": "Enabled",
|
||||
"plugins.edit.title": "Edit MCP server",
|
||||
"plugins.edit.titleNamed": "Edit MCP: {sid}",
|
||||
"profile.avatar": "Avatar",
|
||||
"profile.avatarHint": "PNG, JPEG, WebP, or GIF, up to 2 MB.",
|
||||
"profile.chatPrefs": "Chat Preferences",
|
||||
|
|
|
|||
|
|
@ -276,6 +276,38 @@ export default {
|
|||
"plugins.toc.install": "安装",
|
||||
"plugins.toc.instances": "实例",
|
||||
"plugins.toc.policy": "策略",
|
||||
"plugins.action.cancel": "取消",
|
||||
"plugins.action.clear": "清空",
|
||||
"plugins.action.delete": "删除",
|
||||
"plugins.action.disable": "禁用",
|
||||
"plugins.action.edit": "编辑",
|
||||
"plugins.action.enable": "启用",
|
||||
"plugins.action.exportJson": "导出 JSON",
|
||||
"plugins.action.exportJsonTitle": "下载 Cursor mcpServers 快照,便于重装/迁移",
|
||||
"plugins.action.health": "健康检查",
|
||||
"plugins.action.install": "安装",
|
||||
"plugins.action.locate": "定位",
|
||||
"plugins.action.save": "保存",
|
||||
"plugins.action.saveBinding": "保存绑定",
|
||||
"plugins.action.saveToolPolicy": "保存工具策略",
|
||||
"plugins.action.selectAll": "全选",
|
||||
"plugins.action.syncTools": "同步 Tools",
|
||||
"plugins.binding.empty": "尚未安装 MCP 服务。",
|
||||
"plugins.binding.hint": "将 MCP 服务绑定到专家(多对多)。",
|
||||
"plugins.binding.reverse": "反向视图:server → specialists",
|
||||
"plugins.binding.specialist": "专家",
|
||||
"plugins.col.action": "操作",
|
||||
"plugins.col.boundSpecialists": "已绑定专家",
|
||||
"plugins.col.commandUrl": "command / url",
|
||||
"plugins.col.enabled": "启用",
|
||||
"plugins.col.health": "健康",
|
||||
"plugins.col.serverId": "server_id",
|
||||
"plugins.col.tools": "tools",
|
||||
"plugins.confirm.delete": "从 MCP 注册表删除 {sid}?",
|
||||
"plugins.edit.configHint": "Cursor 服务配置(单个 mcpServers 值)",
|
||||
"plugins.edit.enabled": "启用",
|
||||
"plugins.edit.title": "编辑 MCP 服务",
|
||||
"plugins.edit.titleNamed": "编辑 MCP:{sid}",
|
||||
"profile.avatar": "头像",
|
||||
"profile.avatarHint": "支持 PNG、JPEG、WebP、GIF,最大 2MB。",
|
||||
"profile.chatPrefs": "对话偏好",
|
||||
|
|
|
|||
|
|
@ -75,8 +75,7 @@ function cursorCommandSummary(cursor) {
|
|||
async function renderPlugins() {
|
||||
document.querySelectorAll("[data-mcp-edit-modal]").forEach((n) => n.remove());
|
||||
document.querySelectorAll("body > .row-actions__menu, body > .chat-sess-menu-pop.row-actions__menu").forEach((n) => n.remove());
|
||||
const p = await apiGet("/admin/api/plugins");
|
||||
let toolPolicy = {
|
||||
const defaultToolPolicy = {
|
||||
disable_tool_confirm: false,
|
||||
enforced_retry_mode: "first_round_only",
|
||||
tool_loop_state_machine: true,
|
||||
|
|
@ -100,17 +99,17 @@ async function renderPlugins() {
|
|||
wecom_longconn_workers: 2,
|
||||
wecom_longconn_inbound_queue_maxsize: 200,
|
||||
};
|
||||
let mcp = { servers: [] };
|
||||
let mcpBinding = { available_specialists: ["generalist"], servers: [], mapping: {} };
|
||||
try {
|
||||
mcp = await apiGet("/admin/api/mcp/servers");
|
||||
} catch (_) {}
|
||||
try {
|
||||
mcpBinding = await apiGet("/admin/api/mcp/binding");
|
||||
} catch (_) {}
|
||||
try {
|
||||
toolPolicy = await apiGet("/admin/api/tool-policy");
|
||||
} catch (_) {}
|
||||
const [p, mcp, mcpBinding, toolPolicyRaw] = await Promise.all([
|
||||
apiGet("/admin/api/plugins"),
|
||||
apiGet("/admin/api/mcp/servers").catch(() => ({ servers: [] })),
|
||||
apiGet("/admin/api/mcp/binding").catch(() => ({
|
||||
available_specialists: ["generalist"],
|
||||
servers: [],
|
||||
mapping: {},
|
||||
})),
|
||||
apiGet("/admin/api/tool-policy").catch(() => null),
|
||||
]);
|
||||
let toolPolicy = toolPolicyRaw && typeof toolPolicyRaw === "object" ? toolPolicyRaw : defaultToolPolicy;
|
||||
|
||||
const pluginCatalog = Array.isArray(p.plugins) ? p.plugins : [];
|
||||
const pluginPageRef = { value: 1 };
|
||||
|
|
@ -222,7 +221,7 @@ async function renderPlugins() {
|
|||
});
|
||||
const saveToolPolicyBtn = el("button", {
|
||||
class: "btn",
|
||||
text: "Save Tool Policy",
|
||||
text: t("plugins.action.saveToolPolicy"),
|
||||
onclick: async () => {
|
||||
const r = await apiPost("/admin/api/tool-policy", {
|
||||
turn_max_tool_workers: Number(turnMaxWorkersInput.value || 8),
|
||||
|
|
@ -312,7 +311,7 @@ async function renderPlugins() {
|
|||
});
|
||||
const locateBtn = el("button", {
|
||||
class: "btn btn--small",
|
||||
text: "Locate",
|
||||
text: t("plugins.action.locate"),
|
||||
onclick: () => flashInstalledRow(sid),
|
||||
});
|
||||
return el("tr", {}, [
|
||||
|
|
@ -327,9 +326,9 @@ async function renderPlugins() {
|
|||
el("table", { class: "table table--compact" }, [
|
||||
el("thead", {}, [
|
||||
el("tr", {}, [
|
||||
el("th", { text: "server_id" }),
|
||||
el("th", { text: "bound specialists" }),
|
||||
el("th", { text: "action" }),
|
||||
el("th", { text: t("plugins.col.serverId") }),
|
||||
el("th", { text: t("plugins.col.boundSpecialists") }),
|
||||
el("th", { text: t("plugins.col.action") }),
|
||||
]),
|
||||
]),
|
||||
el("tbody", {}, rows.length ? rows : [el("tr", {}, [el("td", { text: "-", colspan: "3" })])]),
|
||||
|
|
@ -350,7 +349,7 @@ async function renderPlugins() {
|
|||
const slice = bindingServers.slice(start, start + PLUGINS_PAGE_SIZE);
|
||||
bindingListRowsMount.innerHTML = "";
|
||||
if (!bindingServers.length) {
|
||||
bindingListRowsMount.appendChild(el("div", { class: "muted", text: "No MCP servers installed yet." }));
|
||||
bindingListRowsMount.appendChild(el("div", { class: "muted", text: t("plugins.binding.empty") }));
|
||||
bindingListPagerMount.innerHTML = "";
|
||||
const blBar0 = pluginsPagerBar(bindingListTotalHolder, bindingListPageRef, renderBindingList);
|
||||
bindingListPagerMount.appendChild(blBar0.wrap);
|
||||
|
|
@ -386,7 +385,7 @@ async function renderPlugins() {
|
|||
});
|
||||
const selectAllBindingBtn = el("button", {
|
||||
class: "btn",
|
||||
text: "Select All",
|
||||
text: t("plugins.action.selectAll"),
|
||||
onclick: () => {
|
||||
const current = String(specialistSelect.value || "");
|
||||
bindingDraft[current] = bindingServers.map((x) => String(x.server_id || "")).filter((x) => x);
|
||||
|
|
@ -396,7 +395,7 @@ async function renderPlugins() {
|
|||
});
|
||||
const clearBindingBtn = el("button", {
|
||||
class: "btn",
|
||||
text: "Clear",
|
||||
text: t("plugins.action.clear"),
|
||||
onclick: () => {
|
||||
const current = String(specialistSelect.value || "");
|
||||
bindingDraft[current] = [];
|
||||
|
|
@ -406,7 +405,7 @@ async function renderPlugins() {
|
|||
});
|
||||
const saveBindingBtn = el("button", {
|
||||
class: "btn",
|
||||
text: "Save Binding",
|
||||
text: t("plugins.action.saveBinding"),
|
||||
onclick: async () => {
|
||||
const r = await apiPost("/admin/api/mcp/binding", { mapping: bindingDraft });
|
||||
bindingStatus.textContent = `[binding] ` + JSON.stringify(r);
|
||||
|
|
@ -435,7 +434,7 @@ async function renderPlugins() {
|
|||
});
|
||||
const installBtn = el("button", {
|
||||
class: "btn",
|
||||
text: "Install",
|
||||
text: t("plugins.action.install"),
|
||||
onclick: async () => {
|
||||
const raw = String(jsonInstallInput.value || "").trim();
|
||||
if (!raw) {
|
||||
|
|
@ -472,8 +471,8 @@ async function renderPlugins() {
|
|||
});
|
||||
const mcpExportJsonBtn = el("button", {
|
||||
class: "btn",
|
||||
text: "Export JSON",
|
||||
title: "Download Cursor mcpServers snapshot for reinstall / migration",
|
||||
text: t("plugins.action.exportJson"),
|
||||
title: t("plugins.action.exportJsonTitle"),
|
||||
onclick: async () => {
|
||||
let r;
|
||||
try {
|
||||
|
|
@ -525,7 +524,7 @@ async function renderPlugins() {
|
|||
|
||||
let editingServer = null;
|
||||
const editModal = el("div", { class: "session-monitor-modal u-hidden", "data-mcp-edit-modal": "1" });
|
||||
const editTitle = el("div", { class: "card__title", text: "Edit MCP server" });
|
||||
const editTitle = el("div", { class: "card__title", text: t("plugins.edit.title") });
|
||||
const editServerIdLab = el("div", { class: "muted", text: "" });
|
||||
const editCursorInput = el("textarea", {
|
||||
class: "input",
|
||||
|
|
@ -551,8 +550,8 @@ async function renderPlugins() {
|
|||
if (!row) return;
|
||||
editingServer = row;
|
||||
const sid = String(row.server_id || "");
|
||||
editTitle.textContent = `Edit MCP: ${sid}`;
|
||||
editServerIdLab.textContent = `server_id: ${sid}`;
|
||||
editTitle.textContent = tf("plugins.edit.titleNamed", { sid });
|
||||
editServerIdLab.textContent = `${t("plugins.col.serverId")}: ${sid}`;
|
||||
const cursor = row.cursor && typeof row.cursor === "object" ? row.cursor : {};
|
||||
editCursorInput.value = JSON.stringify(cursor, null, 2);
|
||||
editEnabledCb.checked = !!row.enabled;
|
||||
|
|
@ -568,7 +567,7 @@ async function renderPlugins() {
|
|||
});
|
||||
const editSaveBtn = el("button", {
|
||||
class: "btn btn--primary",
|
||||
text: "Save",
|
||||
text: t("plugins.action.save"),
|
||||
onclick: async () => {
|
||||
if (!editingServer) return;
|
||||
const sid = String(editingServer.server_id || "").trim();
|
||||
|
|
@ -608,16 +607,16 @@ async function renderPlugins() {
|
|||
el("div", { class: "card session-monitor-modal__card", style: "width:min(720px,96vw);" }, [
|
||||
editTitle,
|
||||
editServerIdLab,
|
||||
el("div", { class: "muted", text: "Cursor server config (single mcpServers value)" }),
|
||||
el("div", { class: "muted", text: t("plugins.edit.configHint") }),
|
||||
editCursorInput,
|
||||
el("div", { class: "row", style: "align-items:center;gap:10px;flex-wrap:wrap;" }, [
|
||||
el("label", { class: "kv" }, [editEnabledCb, document.createTextNode(" Enabled")]),
|
||||
el("label", { class: "kv" }, [editEnabledCb, document.createTextNode(` ${t("plugins.edit.enabled")}`)]),
|
||||
el("label", { text: "timeout_s" }),
|
||||
editTimeoutInput,
|
||||
]),
|
||||
editStatus,
|
||||
el("div", { class: "row u-row-end", style: "gap:8px;margin-top:10px;" }, [
|
||||
el("button", { class: "btn", text: "Cancel", onclick: closeEditModal }),
|
||||
el("button", { class: "btn", text: t("plugins.action.cancel"), onclick: closeEditModal }),
|
||||
editSaveBtn,
|
||||
]),
|
||||
]),
|
||||
|
|
@ -645,11 +644,11 @@ async function renderPlugins() {
|
|||
const cursor = x.cursor && typeof x.cursor === "object" ? x.cursor : {};
|
||||
const actions = rowActions("⋯", [
|
||||
{
|
||||
label: "Edit",
|
||||
label: t("plugins.action.edit"),
|
||||
onClick: () => openEditModal(x),
|
||||
},
|
||||
{
|
||||
label: x.enabled ? "Disable" : "Enable",
|
||||
label: x.enabled ? t("plugins.action.disable") : t("plugins.action.enable"),
|
||||
onClick: async () => {
|
||||
await apiPost("/admin/api/mcp/toggle", { server_id: sid, enabled: !x.enabled });
|
||||
markPrewarmReminder("mcp_toggled");
|
||||
|
|
@ -658,7 +657,7 @@ async function renderPlugins() {
|
|||
},
|
||||
},
|
||||
{
|
||||
label: "Health",
|
||||
label: t("plugins.action.health"),
|
||||
onClick: async () => {
|
||||
const r = await apiPost("/admin/api/mcp/healthcheck", { server_id: sid });
|
||||
installStatus.textContent = `[health:${sid}] ` + JSON.stringify(r);
|
||||
|
|
@ -666,7 +665,7 @@ async function renderPlugins() {
|
|||
},
|
||||
},
|
||||
{
|
||||
label: "Sync Tools",
|
||||
label: t("plugins.action.syncTools"),
|
||||
onClick: async () => {
|
||||
const r = await apiPost("/admin/api/mcp/tools/sync", { server_id: sid });
|
||||
installStatus.textContent = `[sync:${sid}] ` + JSON.stringify(r);
|
||||
|
|
@ -674,10 +673,10 @@ async function renderPlugins() {
|
|||
},
|
||||
},
|
||||
{
|
||||
label: "Delete",
|
||||
label: t("plugins.action.delete"),
|
||||
danger: true,
|
||||
onClick: async () => {
|
||||
if (!window.confirm(`Delete ${sid} from MCP registry?`)) return;
|
||||
if (!window.confirm(tf("plugins.confirm.delete", { sid }))) return;
|
||||
const r = await apiPost("/admin/api/mcp/delete", { server_id: sid });
|
||||
installStatus.textContent = `[delete:${sid}] ` + JSON.stringify(r);
|
||||
markPrewarmReminder("mcp_deleted");
|
||||
|
|
@ -809,11 +808,11 @@ async function renderPlugins() {
|
|||
el("table", { class: "table table--compact" }, [
|
||||
el("thead", {}, [
|
||||
el("tr", {}, [
|
||||
el("th", { text: "server_id" }),
|
||||
el("th", { text: "command / url" }),
|
||||
el("th", { text: "tools" }),
|
||||
el("th", { text: "enabled" }),
|
||||
el("th", { text: "health" }),
|
||||
el("th", { text: t("plugins.col.serverId") }),
|
||||
el("th", { text: t("plugins.col.commandUrl") }),
|
||||
el("th", { text: t("plugins.col.tools") }),
|
||||
el("th", { text: t("plugins.col.enabled") }),
|
||||
el("th", { text: t("plugins.col.health") }),
|
||||
el("th", { class: "table__cell--actions", text: t("tenants.rowActions") }),
|
||||
]),
|
||||
]),
|
||||
|
|
@ -845,16 +844,16 @@ async function renderPlugins() {
|
|||
]);
|
||||
|
||||
const foldMcpBinding = pluginsFold(t("plugins.fold.bindingEdit"), [
|
||||
el("div", { class: "muted", text: "Bind MCP servers to specialists (many-to-many)." }),
|
||||
el("div", { class: "muted", text: t("plugins.binding.hint") }),
|
||||
el("div", { class: "row" }, [
|
||||
el("label", { text: "Specialist" }),
|
||||
el("label", { text: t("plugins.binding.specialist") }),
|
||||
specialistSelect,
|
||||
selectAllBindingBtn,
|
||||
clearBindingBtn,
|
||||
saveBindingBtn,
|
||||
]),
|
||||
bindingListWrap,
|
||||
el("div", { class: "muted", text: "Reverse view: server -> specialists" }),
|
||||
el("div", { class: "muted", text: t("plugins.binding.reverse") }),
|
||||
bindingReverseWrap,
|
||||
bindingStatus,
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -1220,18 +1220,13 @@ async function renderSkills() {
|
|||
};
|
||||
|
||||
const refreshSkillsState = async () => {
|
||||
await loadRows();
|
||||
await loadAudits();
|
||||
await loadSkillBinding();
|
||||
await Promise.all([loadRows(), loadAudits(), loadSkillBinding()]);
|
||||
repaint();
|
||||
renderSkillBindingList();
|
||||
};
|
||||
|
||||
try {
|
||||
await loadRows();
|
||||
await loadAudits();
|
||||
await loadSkillBinding();
|
||||
await loadSkillMode();
|
||||
await Promise.all([loadRows(), loadAudits(), loadSkillBinding(), loadSkillMode()]);
|
||||
const rolesForPreview = (
|
||||
Array.isArray(skillBindingState.roles) && skillBindingState.roles.length
|
||||
? skillBindingState.roles
|
||||
|
|
@ -1378,8 +1373,7 @@ async function renderSkills() {
|
|||
llmToolsBox.addEventListener("toggle", async () => {
|
||||
if (!llmToolsBox.open || lazyLoadState.llmLoaded) return;
|
||||
lazyLoadState.llmLoaded = true;
|
||||
await loadExposureTraceSetting();
|
||||
await loadLLMToolsPreview(llmRoleSelect.value);
|
||||
await Promise.all([loadExposureTraceSetting(), loadLLMToolsPreview(llmRoleSelect.value)]);
|
||||
});
|
||||
selfCheckBox.addEventListener("toggle", async () => {
|
||||
if (!selfCheckBox.open || lazyLoadState.selfCheckLoaded) return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue