mirror of
https://github.com/TautvydasDerzinskas/Thingport.git
synced 2026-10-21 22:22:24 -05:00
feat(frontend): offer the MCP tools that change the library, with a confirm
They're marked as changing the library, and turning one on asks first.
This commit is contained in:
1 parent
a36a99639a
commit
699fa8a1c5
3 files changed
+56
-6
No files matched your search
@@ -246,8 +246,27 @@
|
||||
"library_stats": {
|
||||
"title": "Library stats",
|
||||
"description": "Your totals, most viewed, most printed and newest models."
|
||||
},
|
||||
"get_import_status": {
|
||||
"title": "Check an import",
|
||||
"description": "Follow an import that's still running."
|
||||
},
|
||||
"import_model": {
|
||||
"title": "Import a model",
|
||||
"description": "Import a model from a link, as + Add > Import does."
|
||||
},
|
||||
"create_collection": {
|
||||
"title": "Create a collection",
|
||||
"description": "Make a new, empty collection."
|
||||
},
|
||||
"add_to_collection": {
|
||||
"title": "Add to a collection",
|
||||
"description": "Put models from your library in one of your collections."
|
||||
}
|
||||
}
|
||||
},
|
||||
"writeConfirmTitle": "Let the assistant use “{{tool}}”?",
|
||||
"writeConfirmMessage": "This tool changes your library. An assistant connected with this token will be able to use it without asking you each time. Nothing it does deletes models.",
|
||||
"writeConfirm": "Turn on"
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
|
||||
@@ -247,8 +247,27 @@
|
||||
"library_stats": {
|
||||
"title": "Bibliotekos statistika",
|
||||
"description": "Jūsų suvestinė, daugiausiai peržiūrėti, spausdinti ir naujausi modeliai."
|
||||
},
|
||||
"get_import_status": {
|
||||
"title": "Importo būsena",
|
||||
"description": "Sekti importą, kuris dar vyksta."
|
||||
},
|
||||
"import_model": {
|
||||
"title": "Importuoti modelį",
|
||||
"description": "Importuoti modelį iš nuorodos, kaip + Pridėti > Importuoti."
|
||||
},
|
||||
"create_collection": {
|
||||
"title": "Sukurti kolekciją",
|
||||
"description": "Sukurti naują, tuščią kolekciją."
|
||||
},
|
||||
"add_to_collection": {
|
||||
"title": "Įtraukti į kolekciją",
|
||||
"description": "Įdėti bibliotekos modelius į vieną iš jūsų kolekcijų."
|
||||
}
|
||||
}
|
||||
},
|
||||
"writeConfirmTitle": "Leisti asistentui naudoti „{{tool}}“?",
|
||||
"writeConfirmMessage": "Šis įrankis keičia jūsų biblioteką. Su šiuo raktu prijungtas asistentas galės jį naudoti kiekvieną kartą jūsų neklausdamas. Jis niekada netrina modelių.",
|
||||
"writeConfirm": "Įjungti"
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
|
||||
@@ -9,6 +9,7 @@ import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { authApi, type ApiTokenInfo, type McpToolInfo } from "../../api/auth";
|
||||
import { UnauthorizedError } from "../../api/client";
|
||||
import { useConfirm } from "../../components/ConfirmProvider";
|
||||
|
||||
type Props = {
|
||||
info: ApiTokenInfo;
|
||||
@@ -20,6 +21,7 @@ type Props = {
|
||||
* unsaved state to lose; a refused save puts the box back. */
|
||||
export default function ApiTokenMcpTools({ info, onChange, onUnauthorized }: Props) {
|
||||
const { t, i18n } = useTranslation(["app", "common"]);
|
||||
const confirm = useConfirm();
|
||||
const [saving, setSaving] = React.useState<string | null>(null);
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
// Ahead of the server while a save is in flight; back in step with it once the save answers.
|
||||
@@ -33,10 +35,20 @@ export default function ApiTokenMcpTools({ info, onChange, onUnauthorized }: Pro
|
||||
return i18n.exists(key, { ns: "app" }) ? t(key) : tool[part];
|
||||
};
|
||||
|
||||
const toggle = async (name: string, on: boolean) => {
|
||||
const toggle = async (tool: McpToolInfo, on: boolean) => {
|
||||
const name = tool.name;
|
||||
// Reading needs no second thought; letting an assistant change the library does.
|
||||
if (on && !tool.read_only) {
|
||||
const ok = await confirm({
|
||||
title: t("profile.apiToken.mcp.writeConfirmTitle", { tool: label(tool, "title") }),
|
||||
message: t("profile.apiToken.mcp.writeConfirmMessage"),
|
||||
confirmLabel: t("profile.apiToken.mcp.writeConfirm"),
|
||||
});
|
||||
if (!ok) return;
|
||||
}
|
||||
const next = info.available_mcp_tools
|
||||
.map((tool) => tool.name)
|
||||
.filter((tool) => (tool === name ? on : enabled.has(tool)));
|
||||
.map((available) => available.name)
|
||||
.filter((other) => (other === name ? on : enabled.has(other)));
|
||||
setSelected(next);
|
||||
setSaving(name);
|
||||
setError(null);
|
||||
@@ -70,7 +82,7 @@ export default function ApiTokenMcpTools({ info, onChange, onUnauthorized }: Pro
|
||||
sx={{ pt: 0.25 }}
|
||||
checked={enabled.has(tool.name)}
|
||||
disabled={saving !== null}
|
||||
onChange={(e) => void toggle(tool.name, e.target.checked)}
|
||||
onChange={(e) => void toggle(tool, e.target.checked)}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
|
||||
Reference in new issue
Block a user