import { useState } from "react"; import { useAsyncData } from "../../lib/useAsyncData"; import { adminListPlugins, adminSetPluginPolicy, adminPluginInstall, adminPluginUninstall, getStoredRole } from "../../lib/api"; import type { AdminPluginRecord } from "../../lib/types"; import { useAutoReload } from "../hooks"; import { useAuditStore } from "../audit"; import { AdminTable, Notice, PageHeader, type AdminColumn } from "../components"; import { Button, Surface, Switch, Tag } from "../../components/primitives"; export function PluginsModule(): React.ReactNode { const { data, loading, error, reload } = useAsyncData(adminListPlugins, []); useAutoReload(reload, 10000); const isOwner = getStoredRole() === "owner"; const log = useAuditStore((s) => s.log); const [busy, setBusy] = useState(null); const [fail, setFail] = useState(null); const [msg, setMsg] = useState(null); const install = () => { setBusy("__install__"); setFail(null); setMsg(null); adminPluginInstall({ name: "sample-plugin", kind: "tool", description: "手工安装示例" }) .then(() => { log("plugin.install", "ok"); setMsg("插件安装成功"); reload(); }) .catch((err: unknown) => { log("plugin.install", "error"); setFail(err instanceof Error ? err.message : "插件安装失败"); }) .finally(() => setBusy(null)); }; const uninstall = (name: string) => { setBusy(name); setFail(null); setMsg(null); adminPluginUninstall({ name }) .then(() => { log("plugin.uninstall", "ok"); setMsg(`已卸载 ${name}`); reload(); }) .catch((err: unknown) => { log("plugin.uninstall", "error"); setFail(err instanceof Error ? err.message : "卸载失败"); }) .finally(() => setBusy(null)); }; const setPolicy = (name: string, allowInGroup: boolean, allowInStranger: boolean) => { setBusy(name); setFail(null); adminSetPluginPolicy(name, allowInGroup, allowInStranger) .then(() => { log(`policy.set:${name}`, "ok"); reload(); }) .catch((err: unknown) => { log(`policy.set:${name}`, "error"); setFail(err instanceof Error ? err.message : "策略更新失败"); }) .finally(() => setBusy(null)); }; const columns: AdminColumn[] = [ { key: "name", title: "名称", render: (p) => {p.name} }, { key: "kind", title: "类型", render: (p) => {p.kind} }, { key: "desc", title: "描述", render: (p) => {p.description || "—"} }, { key: "policy", title: "环境授权(owner)", render: (p) => ( {busy === p.name ? 保存中… : null} ), }, { key: "actions", title: "操作", render: (p) => ( ), }, ]; return (
安装插件 } /> {!isOwner ? 当前角色为 {getStoredRole()},工具策略仅 owner 可写(读取/查看可见)。 : null} {fail ? {fail} : null} {msg ? {msg} : null} p.name} /> 工具 schema / 技能 / MCP 服务器列表为后端 M10+ 提供;此页展示已注册能力及其环境可见性标记(群聊 / 陌生人默认关闭)。
); }