返回 DeepSeek-Reasonix
SessionExperienceSettings.tsx
根目录 / desktop / frontend / src / components / SessionExperienceSettings.tsx
1 import { useCallback, useEffect, useState } from "react";
2 import { SettingsOptions } from "./SettingsOptions";
3 import { ShieldCheck } from "lucide-react";
4 import { app } from "../lib/bridge";
5 import { useT } from "../lib/i18n";
6 import type { SettingsView } from "../lib/types";
7 import { SettingsField, SettingsSection } from "./SettingsForm";
8 import { normalizeToolApprovalMode } from "../lib/types";
9 import { RiskConfirmation } from "./RiskConfirmation";
10
11 const TOOL_APPROVAL_MODES = ["read-only", "workspace-write", "danger-full-access"] as const;
12
13 type Props = {
14 snapshot: SettingsView;
15 busy: boolean;
16 apply: (write: () => Promise<unknown>) => Promise<boolean>;
17 };
18
19 export function SessionExperienceSettings({ snapshot, busy, apply }: Props) {
20 const t = useT();
21 const defaultToolApprovalMode = normalizeToolApprovalMode(snapshot.defaultToolApprovalMode);
22 const [confirmingFullAccess, setConfirmingFullAccess] = useState(false);
23 const [acknowledged, setAcknowledged] = useState(false);
24 const closeConfirmation = useCallback(() => {
25 setAcknowledged(false);
26 setConfirmingFullAccess(false);
27 }, []);
28 useEffect(() => {
29 if (busy) closeConfirmation();
30 }, [busy, closeConfirmation]);
31 const saveApproval = (next: (typeof TOOL_APPROVAL_MODES)[number]) => {
32 if (next === defaultToolApprovalMode) return;
33 if (next === "danger-full-access") {
34 setAcknowledged(false);
35 setConfirmingFullAccess(true);
36 return;
37 }
38 void apply(() => app.SetDefaultToolApprovalMode(next));
39 };
40 const confirmFullAccess = () => {
41 if (busy || !acknowledged) return;
42 closeConfirmation();
43 void apply(() => app.SetDefaultToolApprovalMode("danger-full-access"));
44 };
45 return <>
46 <SettingsSection title={t("settings.general.sectionConversation")}>
47 <SettingsField label={t("settings.defaultToolApprovalMode")} hint={t("settings.defaultToolApprovalModeHint")} icon={<ShieldCheck size={18} />}>
48 <SettingsOptions layout="field" className="set-seg" role="radiogroup" aria-label={t("settings.defaultToolApprovalMode")}>
49 {TOOL_APPROVAL_MODES.map((value) => <button key={value} type="button" className={`set-seg__btn${defaultToolApprovalMode === value ? " set-seg__btn--on" : ""}`} role="radio" aria-checked={defaultToolApprovalMode === value} disabled={busy || confirmingFullAccess} onClick={() => saveApproval(value)}>{t(`settings.defaultToolApprovalMode.${value}`)}</button>)}
50 </SettingsOptions>
51 </SettingsField>
52 </SettingsSection>
53 <RiskConfirmation
54 open={confirmingFullAccess}
55 title={t("permission.fullAccessConfirm.title")}
56 description={t("permission.fullAccessConfirm.futureDescription")}
57 acknowledgeLabel={t("permission.fullAccessConfirm.futureAcknowledge")}
58 cancelLabel={t("common.cancel")}
59 closeLabel={t("common.close")}
60 confirmLabel={t("permission.fullAccessConfirm.enable")}
61 acknowledged={acknowledged}
62 disabled={busy}
63 onAcknowledgedChange={setAcknowledged}
64 onCancel={closeConfirmation}
65 onConfirm={confirmFullAccess}
66 />
67 </>;
68 }
69
69 lines Plain Text