diff --git a/assets/tldraw-license-key-settings.png b/assets/tldraw-license-key-settings.png new file mode 100644 index 000000000..9b875279e Binary files /dev/null and b/assets/tldraw-license-key-settings.png differ diff --git a/backend/internal/repository/repository.go b/backend/internal/repository/repository.go index 3e2ca3aae..c9c21898b 100644 --- a/backend/internal/repository/repository.go +++ b/backend/internal/repository/repository.go @@ -590,6 +590,17 @@ func (r *Repository) SaveSystemSetting(setting *model.SystemSetting) error { return r.db.Save(setting).Error } +func (r *Repository) SaveSystemSettings(settings ...*model.SystemSetting) error { + return r.db.Transaction(func(tx *gorm.DB) error { + for _, setting := range settings { + if err := tx.Save(setting).Error; err != nil { + return err + } + } + return nil + }) +} + func (r *Repository) DeleteSystemSetting(key string) error { return r.db.Delete(&model.SystemSetting{}, "key = ?", key).Error } diff --git a/backend/internal/service/drawing_engine.go b/backend/internal/service/drawing_engine.go index c15c0f021..0d2a1d072 100644 --- a/backend/internal/service/drawing_engine.go +++ b/backend/internal/service/drawing_engine.go @@ -11,7 +11,10 @@ import ( "gorm.io/gorm" ) -const drawingEngineSettingKey = "drawing_engine" +const ( + drawingEngineSettingKey = "drawing_engine" + tldrawLicenseKeySettingKey = "tldraw_license_key" +) const ( DrawingEngineTldraw = "tldraw" @@ -19,7 +22,8 @@ const ( ) type DrawingEngineSetting struct { - DefaultEngine string `json:"defaultEngine"` + DefaultEngine string `json:"defaultEngine"` + TldrawLicenseKey string `json:"tldrawLicenseKey"` } type PublicDrawingEngineSetting struct { @@ -57,11 +61,22 @@ func (s *Service) UpdateDrawingEngineSetting(actor *model.User, value DrawingEng if err := validateDrawingEngineSetting(value); err != nil { return nil, err } + value.TldrawLicenseKey = strings.TrimSpace(value.TldrawLicenseKey) current, before, err := s.readDrawingEngineSetting() if err != nil { return nil, err } - encoded, err := json.Marshal(value) + currentLicenseSetting, _, err := s.readTldrawLicenseKey() + if err != nil { + return nil, err + } + encoded, err := json.Marshal(struct { + DefaultEngine string `json:"defaultEngine"` + }{DefaultEngine: value.DefaultEngine}) + if err != nil { + return nil, err + } + encodedLicenseKey, err := json.Marshal(value.TldrawLicenseKey) if err != nil { return nil, err } @@ -69,10 +84,14 @@ func (s *Service) UpdateDrawingEngineSetting(actor *model.User, value DrawingEng if current != nil { setting.CreatedAt = current.CreatedAt } - if err := s.repo.SaveSystemSetting(&setting); err != nil { + licenseSetting := model.SystemSetting{Key: tldrawLicenseKeySettingKey, ValueJSON: string(encodedLicenseKey), UpdatedBy: actor.ID} + if currentLicenseSetting != nil { + licenseSetting.CreatedAt = currentLicenseSetting.CreatedAt + } + if err := s.repo.SaveSystemSettings(&setting, &licenseSetting); err != nil { return nil, err } - if err := s.appendAdminAudit(actor, "drawing_engine.update", "system_setting", drawingEngineSettingKey, "更新默认绘图工具", map[string]any{"before": before, "after": value}); err != nil { + if err := s.appendAdminAudit(actor, "drawing_engine.update", "system_setting", drawingEngineSettingKey, "更新绘图工具配置", map[string]any{"before": drawingEngineAuditValue(before), "after": drawingEngineAuditValue(value)}); err != nil { return nil, err } return publicDrawingEngineSetting(&setting, value), nil @@ -80,22 +99,42 @@ func (s *Service) UpdateDrawingEngineSetting(actor *model.User, value DrawingEng func (s *Service) readDrawingEngineSetting() (*model.SystemSetting, DrawingEngineSetting, error) { setting, err := s.repo.SystemSetting(drawingEngineSettingKey) + value := defaultDrawingEngineSetting() if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, defaultDrawingEngineSetting(), nil + setting = nil + } else if err != nil { + return nil, DrawingEngineSetting{}, err + } else { + if strings.TrimSpace(setting.ValueJSON) == "" || json.Unmarshal([]byte(setting.ValueJSON), &value) != nil { + return nil, DrawingEngineSetting{}, errors.New("绘图工具配置格式无效") + } + if err := validateDrawingEngineSetting(value); err != nil { + return nil, DrawingEngineSetting{}, err + } } + _, licenseKey, err := s.readTldrawLicenseKey() if err != nil { return nil, DrawingEngineSetting{}, err } - value := DrawingEngineSetting{} - if strings.TrimSpace(setting.ValueJSON) == "" || json.Unmarshal([]byte(setting.ValueJSON), &value) != nil { - return nil, DrawingEngineSetting{}, errors.New("绘图工具配置格式无效") - } - if err := validateDrawingEngineSetting(value); err != nil { - return nil, DrawingEngineSetting{}, err - } + value.TldrawLicenseKey = licenseKey return setting, value, nil } +func (s *Service) readTldrawLicenseKey() (*model.SystemSetting, string, error) { + setting, err := s.repo.SystemSetting(tldrawLicenseKeySettingKey) + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, "", nil + } + if err != nil { + return nil, "", err + } + var value string + if strings.TrimSpace(setting.ValueJSON) == "" || json.Unmarshal([]byte(setting.ValueJSON), &value) != nil { + return nil, "", errors.New("tldraw License Key 配置格式无效") + } + return setting, strings.TrimSpace(value), nil +} + func validateDrawingEngineSetting(value DrawingEngineSetting) error { if value.DefaultEngine != DrawingEngineTldraw && value.DefaultEngine != DrawingEngineExcalidraw { return BadAuthRequest("默认绘图工具必须是 tldraw 或 Excalidraw") @@ -103,6 +142,10 @@ func validateDrawingEngineSetting(value DrawingEngineSetting) error { return nil } +func drawingEngineAuditValue(value DrawingEngineSetting) map[string]any { + return map[string]any{"defaultEngine": value.DefaultEngine, "hasTldrawLicenseKey": strings.TrimSpace(value.TldrawLicenseKey) != ""} +} + func publicDrawingEngineSetting(setting *model.SystemSetting, value DrawingEngineSetting) *PublicDrawingEngineSetting { result := &PublicDrawingEngineSetting{DrawingEngineSetting: value, Configured: setting != nil} if setting != nil { diff --git a/backend/internal/service/drawing_engine_test.go b/backend/internal/service/drawing_engine_test.go index 643020be0..986f878ff 100644 --- a/backend/internal/service/drawing_engine_test.go +++ b/backend/internal/service/drawing_engine_test.go @@ -1,6 +1,16 @@ package service -import "testing" +import ( + "encoding/json" + "strings" + "testing" + + "infinite-canvas/backend/internal/model" + "infinite-canvas/backend/internal/repository" + + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) func TestDefaultDrawingEngineUsesExcalidraw(t *testing.T) { setting := defaultDrawingEngineSetting() @@ -19,3 +29,53 @@ func TestValidateDrawingEngineSetting(t *testing.T) { t.Fatal("validate unknown engine = nil") } } + +func TestUpdateDrawingEngineSettingKeepsDefaultEngineAndStoresTldrawLicenseSeparately(t *testing.T) { + db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) + if err != nil { + t.Fatal(err) + } + if sqlDB, err := db.DB(); err == nil { + sqlDB.SetMaxOpenConns(1) + } + if err := db.AutoMigrate(&model.SystemSetting{}, &model.AdminAuditEvent{}); err != nil { + t.Fatal(err) + } + repo := repository.New(db) + svc := New(repo, t.TempDir()) + actor := &model.User{ID: "admin-1", Role: model.UserRoleAdmin} + + setting, err := svc.UpdateDrawingEngineSetting(actor, DrawingEngineSetting{ + DefaultEngine: DrawingEngineExcalidraw, + TldrawLicenseKey: "license-key-for-test", + }) + if err != nil { + t.Fatal(err) + } + if setting.DefaultEngine != DrawingEngineExcalidraw { + t.Fatalf("default engine = %q, want %q", setting.DefaultEngine, DrawingEngineExcalidraw) + } + if setting.TldrawLicenseKey != "license-key-for-test" { + t.Fatalf("license key = %q", setting.TldrawLicenseKey) + } + + licenseSetting, err := repo.SystemSetting(tldrawLicenseKeySettingKey) + if err != nil { + t.Fatal(err) + } + var savedLicenseKey string + if err := json.Unmarshal([]byte(licenseSetting.ValueJSON), &savedLicenseKey); err != nil { + t.Fatal(err) + } + if savedLicenseKey != "license-key-for-test" { + t.Fatalf("stored license key = %q", savedLicenseKey) + } + + engineSetting, err := repo.SystemSetting(drawingEngineSettingKey) + if err != nil { + t.Fatal(err) + } + if strings.Contains(engineSetting.ValueJSON, "license-key-for-test") { + t.Fatalf("drawing engine setting must not contain the license key: %s", engineSetting.ValueJSON) + } +} diff --git a/web/src/components/canvas/canvas-drawing-editor-modal.tsx b/web/src/components/canvas/canvas-drawing-editor-modal.tsx index efb9615ed..1cf579805 100644 --- a/web/src/components/canvas/canvas-drawing-editor-modal.tsx +++ b/web/src/components/canvas/canvas-drawing-editor-modal.tsx @@ -6,6 +6,7 @@ import type { CanvasDrawingEditorHandle } from "@/components/canvas/canvas-drawi import { drawingEngineForNode, drawingEngineLabel, isDrawingEngineAvailable } from "@/lib/canvas/canvas-drawing-engine"; import { loadCanvasDrawing, saveCanvasDrawing, type CanvasDrawingSnapshot } from "@/lib/canvas/canvas-drawing-storage"; import { useThemeStore } from "@/stores/use-theme-store"; +import { useUserStore } from "@/stores/use-user-store"; import type { CanvasNodeData } from "@/types/canvas"; const CanvasDrawingTldrawEditor = lazy(() => import("@/components/canvas/canvas-drawing-tldraw-editor").then((module) => ({ default: module.CanvasDrawingTldrawEditor }))); @@ -22,6 +23,7 @@ type CanvasDrawingEditorModalProps = { export function CanvasDrawingEditorModal({ open, projectId, node, onClose, onSaved }: CanvasDrawingEditorModalProps) { const { message } = App.useApp(); const colorScheme = useThemeStore((state) => state.theme); + const tldrawLicenseKey = useUserStore((state) => state.drawingEngine.tldrawLicenseKey); const engine = drawingEngineForNode(node); const currentRef = useRef(null); const editorRef = useRef(null); @@ -76,7 +78,7 @@ export function CanvasDrawingEditorModal({ open, projectId, node, onClose, onSav onClose(); }; - const unavailable = !isDrawingEngineAvailable(engine); + const unavailable = !isDrawingEngineAvailable(engine, tldrawLicenseKey); return ( void handleClose()} footer={null} closable={false} destroyOnHidden width="100vw" centered styles={{ body: { padding: 0 }, container: { padding: 0, overflow: "hidden" } }} className="canvas-drawing-editor-modal">
diff --git a/web/src/components/canvas/canvas-drawing-tldraw-editor.tsx b/web/src/components/canvas/canvas-drawing-tldraw-editor.tsx index b11e5ebef..b293d9886 100644 --- a/web/src/components/canvas/canvas-drawing-tldraw-editor.tsx +++ b/web/src/components/canvas/canvas-drawing-tldraw-editor.tsx @@ -4,12 +4,15 @@ import type { Editor } from "tldraw"; import "tldraw/tldraw.css"; import type { CanvasDrawingEditorHandle, CanvasDrawingEditorProps } from "@/components/canvas/canvas-drawing-editor-types"; +import { resolveTldrawLicenseKey } from "@/lib/canvas/canvas-drawing-engine"; +import { useUserStore } from "@/stores/use-user-store"; const SINGLE_PAGE_OPTIONS = { maxPages: 1 } as const; const DRAWING_RENDER_MAX_DIMENSION = 2048; const DRAWING_RENDER_PADDING = 24; export const CanvasDrawingTldrawEditor = forwardRef(function CanvasDrawingTldrawEditor({ snapshot, colorScheme, onReady }, ref) { + const tldrawLicenseKey = useUserStore((state) => state.drawingEngine.tldrawLicenseKey); const store = useMemo(() => { const next = createTLStore(); if (snapshot) loadSnapshot(next, snapshot as never); @@ -46,7 +49,7 @@ export const CanvasDrawingTldrawEditor = forwardRef { editorRef.current = editor; // 绘图节点只保留单页,避免预览和生成引用出现页选择歧义。 @@ -61,4 +64,4 @@ export const CanvasDrawingTldrawEditor = forwardRef ); -}); +}); \ No newline at end of file diff --git a/web/src/lib/canvas/canvas-drawing-engine.ts b/web/src/lib/canvas/canvas-drawing-engine.ts index ab431e073..8a5cc761e 100644 --- a/web/src/lib/canvas/canvas-drawing-engine.ts +++ b/web/src/lib/canvas/canvas-drawing-engine.ts @@ -4,6 +4,7 @@ export type CanvasDrawingEngine = "tldraw" | "excalidraw"; export type CanvasDrawingEngineSetting = { defaultEngine: CanvasDrawingEngine; + tldrawLicenseKey?: string; configured?: boolean; updatedBy?: string; createdAt?: string; @@ -17,10 +18,14 @@ export function drawingEngineForNode(node?: Pick | n return node?.metadata?.drawingEngine === "excalidraw" ? "excalidraw" : "tldraw"; } -export function isDrawingEngineAvailable(engine: CanvasDrawingEngine) { - return engine === "excalidraw" || import.meta.env.DEV || Boolean(import.meta.env.VITE_TLDRAW_LICENSE_KEY); +export function resolveTldrawLicenseKey(configuredLicenseKey?: string) { + return configuredLicenseKey?.trim() || import.meta.env.VITE_TLDRAW_LICENSE_KEY?.trim() || undefined; +} + +export function isDrawingEngineAvailable(engine: CanvasDrawingEngine, configuredLicenseKey?: string) { + return engine === "excalidraw" || Boolean(resolveTldrawLicenseKey(configuredLicenseKey)); } export function drawingEngineLabel(engine: CanvasDrawingEngine) { return engine === "excalidraw" ? "Excalidraw" : "tldraw"; -} +} \ No newline at end of file diff --git a/web/src/pages/admin/settings/drawing-engine-settings-page.tsx b/web/src/pages/admin/settings/drawing-engine-settings-page.tsx index fc774cd1c..9fa9db54e 100644 --- a/web/src/pages/admin/settings/drawing-engine-settings-page.tsx +++ b/web/src/pages/admin/settings/drawing-engine-settings-page.tsx @@ -1,4 +1,4 @@ -import { App, Button, Segmented, Tag } from "antd"; +import { App, Button, Input, Segmented, Tag } from "antd"; import { Brush, Save } from "lucide-react"; import { useEffect, useState } from "react"; @@ -13,6 +13,7 @@ export default function DrawingEngineSettingsPage() { const current = useUserStore((state) => state.drawingEngine); const setDrawingEngine = useUserStore((state) => state.setDrawingEngine); const [engine, setEngine] = useState(current.defaultEngine); + const [tldrawLicenseKey, setTldrawLicenseKey] = useState(current.tldrawLicenseKey || ""); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); @@ -22,6 +23,7 @@ export default function DrawingEngineSettingsPage() { if (cancelled) return; setDrawingEngine(setting); setEngine(setting.defaultEngine); + setTldrawLicenseKey(setting.tldrawLicenseKey || ""); }).catch((error) => { if (!cancelled) message.error(error instanceof Error ? error.message : "读取绘图工具配置失败"); }).finally(() => { @@ -30,17 +32,19 @@ export default function DrawingEngineSettingsPage() { return () => { cancelled = true; }; }, [message, setDrawingEngine]); + const tldrawAvailable = isDrawingEngineAvailable("tldraw", tldrawLicenseKey); const save = async () => { - if (!isDrawingEngineAvailable(engine)) { - message.error("当前生产构建未配置 tldraw License Key"); + if (!isDrawingEngineAvailable(engine, tldrawLicenseKey)) { + message.error("请先配置有效的 tldraw License Key"); return; } setSaving(true); try { - const { setting } = await updateAdminDrawingEngineSetting(engine); + const { setting } = await updateAdminDrawingEngineSetting({ defaultEngine: engine, tldrawLicenseKey }); setDrawingEngine(setting); setEngine(setting.defaultEngine); - message.success("默认绘图工具已更新"); + setTldrawLicenseKey(setting.tldrawLicenseKey || ""); + message.success("绘图工具配置已更新"); } catch (error) { message.error(error instanceof Error ? error.message : "保存绘图工具配置失败"); } finally { @@ -48,28 +52,35 @@ export default function DrawingEngineSettingsPage() { } }; - const dirty = engine !== current.defaultEngine; + const dirty = engine !== current.defaultEngine || tldrawLicenseKey !== (current.tldrawLicenseKey || ""); return (
} title="默认绘图引擎" description="已有绘图保持原引擎,仅新建绘图使用这里的选择。" status={{drawingEngineLabel(current.defaultEngine)}}> -
- - block - className="w-full sm:max-w-md" - disabled={loading || saving} - value={engine} - onChange={setEngine} - options={[ - { label: "Excalidraw", value: "excalidraw" }, - { label: "tldraw", value: "tldraw", disabled: !isDrawingEngineAvailable("tldraw") }, - ]} - /> - +
+
+ + setTldrawLicenseKey(event.target.value)} placeholder="输入 tldraw License Key" disabled={loading || saving} autoComplete="off" /> +

填入有效的 License Key 后保存,即可解锁 tldraw 选项。

+
+
+ + block + className="w-full sm:max-w-md" + disabled={loading || saving} + value={engine} + onChange={setEngine} + options={[ + { label: "Excalidraw", value: "excalidraw" }, + { label: "tldraw", value: "tldraw", disabled: !tldrawAvailable }, + ]} + /> + +
- {!isDrawingEngineAvailable("tldraw") ?
当前生产构建没有 tldraw License Key,不能将其设为新建默认值。
: null} + {!tldrawAvailable ?
当前未配置 tldraw License Key,不能将其设为新建默认值。
: null}
); -} +} \ No newline at end of file diff --git a/web/src/pages/canvas/use-canvas-connection-controller.ts b/web/src/pages/canvas/use-canvas-connection-controller.ts index a93eb4b50..068790b63 100644 --- a/web/src/pages/canvas/use-canvas-connection-controller.ts +++ b/web/src/pages/canvas/use-canvas-connection-controller.ts @@ -8,6 +8,7 @@ import { attachNodeToStoryboardRow, createCanvasNode, getConnectionTargetAnchor, import { createCanvasDrawingFromImage } from "@/lib/canvas/canvas-drawing-storage"; import { isDrawingEngineAvailable, type CanvasDrawingEngine } from "@/lib/canvas/canvas-drawing-engine"; import { isFrameNode, isNodeHiddenByCollapsedFrame } from "@/lib/canvas/canvas-frame"; +import { useUserStore } from "@/stores/use-user-store"; import { CanvasNodeType, type CanvasConnection, type CanvasNodeData, type ConnectionHandle, type ContextMenuState, type Position, type ViewportTransform } from "@/types/canvas"; type UseCanvasConnectionControllerOptions = { @@ -55,6 +56,7 @@ export function useCanvasConnectionController({ setDrawingNodeId, }: UseCanvasConnectionControllerOptions) { const { message } = App.useApp(); + const tldrawLicenseKey = useUserStore((state) => state.drawingEngine.tldrawLicenseKey); const [connectingParams, setConnectingParams] = useState(null); const [connectionTargetNodeId, setConnectionTargetNodeId] = useState(null); const [connectionTargetAnchorRatio, setConnectionTargetAnchorRatio] = useState(); @@ -114,7 +116,7 @@ export function useCanvasConnectionController({ }, [connectionsRef, message, nodesRef, setConnections, setContextMenu, setNodes]); const createConnectedNode = useCallback(async (type: CanvasNodeType.Image | CanvasNodeType.Text | CanvasNodeType.Script | CanvasNodeType.Video | CanvasNodeType.Audio | CanvasNodeType.Drawing, pending: PendingConnectionCreate) => { - if (type === CanvasNodeType.Drawing && !isDrawingEngineAvailable(defaultDrawingEngine)) { + if (type === CanvasNodeType.Drawing && !isDrawingEngineAvailable(defaultDrawingEngine, tldrawLicenseKey)) { message.error("当前生产构建未配置 tldraw License Key,不能创建 tldraw 绘图"); return; } @@ -190,7 +192,7 @@ export function useCanvasConnectionController({ else if (type !== CanvasNodeType.Text && type !== CanvasNodeType.Script && type !== CanvasNodeType.Audio) setDialogNodeId(newNode.id); closeConnectionCreateMenu(); setConnecting(null); - }, [closeConnectionCreateMenu, defaultDrawingEngine, message, nodesRef, projectId, setConnecting, setConnections, setDialogNodeId, setDrawingNodeId, setNodes, setSelectedConnectionId, setSelectedNodeIds]); + }, [closeConnectionCreateMenu, defaultDrawingEngine, message, nodesRef, projectId, setConnecting, setConnections, setDialogNodeId, setDrawingNodeId, setNodes, setSelectedConnectionId, setSelectedNodeIds, tldrawLicenseKey]); const getConnectionDropTarget = useCallback((clientX: number, clientY: number, current: ConnectionHandle): ConnectionDropTarget => { const world = screenToCanvas(clientX, clientY); diff --git a/web/src/pages/canvas/use-canvas-node-operations.ts b/web/src/pages/canvas/use-canvas-node-operations.ts index 1f6f3a9fc..4a511a4fc 100644 --- a/web/src/pages/canvas/use-canvas-node-operations.ts +++ b/web/src/pages/canvas/use-canvas-node-operations.ts @@ -10,6 +10,7 @@ import { isolateCopiedNodeMetadata } from "@/lib/canvas/canvas-node-copy"; import { CanvasNodeType, type CanvasConnection, type CanvasNodeData, type ContextMenuState, type Position } from "@/types/canvas"; import { cloneCanvasDrawing } from "@/lib/canvas/canvas-drawing-storage"; import { isDrawingEngineAvailable, type CanvasDrawingEngine } from "@/lib/canvas/canvas-drawing-engine"; +import { useUserStore } from "@/stores/use-user-store"; type CanvasClipboard = { nodes: CanvasNodeData[]; @@ -52,6 +53,7 @@ export function useCanvasNodeOperations({ onNodesDeleted, }: UseCanvasNodeOperationsOptions) { const { message } = App.useApp(); + const tldrawLicenseKey = useUserStore((state) => state.drawingEngine.tldrawLicenseKey); const clipboardRef = useRef(null); const preferCopiedNodesRef = useRef(false); const markerWritePendingRef = useRef(false); @@ -120,7 +122,7 @@ export function useCanvasNodeOperations({ }, [selectedNodeIdsRef, setSelectedConnectionId, setSelectedNodeIds]); const createNode = useCallback((type: CanvasNodeType, position?: Position) => { - if (type === CanvasNodeType.Drawing && !isDrawingEngineAvailable(defaultDrawingEngine)) { + if (type === CanvasNodeType.Drawing && !isDrawingEngineAvailable(defaultDrawingEngine, tldrawLicenseKey)) { message.error("当前生产构建未配置 tldraw License Key,不能创建 tldraw 绘图"); return; } @@ -128,7 +130,7 @@ export function useCanvasNodeOperations({ commitNodes([...nodesRef.current, node]); selectNodes(new Set([node.id])); if (type !== CanvasNodeType.Text && type !== CanvasNodeType.Script && type !== CanvasNodeType.Audio && type !== CanvasNodeType.Frame && type !== CanvasNodeType.Drawing) setDialogNodeId(node.id); - }, [commitNodes, defaultDrawingEngine, getCanvasCenter, message, nodesRef, selectNodes, setDialogNodeId]); + }, [commitNodes, defaultDrawingEngine, getCanvasCenter, message, nodesRef, selectNodes, setDialogNodeId, tldrawLicenseKey]); const arrangeSelectedNodes = useCallback((mode: "row" | "column" | "grid" | "flow") => { const selected = nodesRef.current.filter((node) => selectedNodeIdsRef.current.has(node.id) && !node.metadata?.locked && !isFrameNode(node)); diff --git a/web/src/services/api/auth.ts b/web/src/services/api/auth.ts index dac454200..5e0dbc70d 100644 --- a/web/src/services/api/auth.ts +++ b/web/src/services/api/auth.ts @@ -437,8 +437,8 @@ export function getAdminDrawingEngineSetting() { return request<{ setting: CanvasDrawingEngineSetting }>(api.get("/admin/settings/drawing-engine")); } -export function updateAdminDrawingEngineSetting(defaultEngine: CanvasDrawingEngineSetting["defaultEngine"]) { - return request<{ setting: CanvasDrawingEngineSetting }>(api.patch("/admin/settings/drawing-engine", { defaultEngine })); +export function updateAdminDrawingEngineSetting(input: Pick) { + return request<{ setting: CanvasDrawingEngineSetting }>(api.patch("/admin/settings/drawing-engine", input)); } export function listAdminApiLogs(params: AdminListParams = {}) {