mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-04-03 14:36:44 +08:00
refactor(openclaw): migrate config panels to TanStack Query hooks
Centralize query keys and extract reusable hooks (useOpenClaw.ts), replacing manual useState/useEffect load/save patterns in Env, Tools, and AgentsDefaults panels for consistency with MCP/Skills modules.
This commit is contained in:
@@ -32,6 +32,7 @@ import {
|
||||
} from "@/lib/api";
|
||||
import { checkAllEnvConflicts, checkEnvConflicts } from "@/lib/api/env";
|
||||
import { useProviderActions } from "@/hooks/useProviderActions";
|
||||
import { openclawKeys } from "@/hooks/useOpenClaw";
|
||||
import { useProxyStatus } from "@/hooks/useProxyStatus";
|
||||
import { useLastValidValue } from "@/hooks/useLastValidValue";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
@@ -458,7 +459,7 @@ function App() {
|
||||
});
|
||||
} else if (activeApp === "openclaw") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["openclawLiveProviderIds"],
|
||||
queryKey: openclawKeys.liveProviderIds,
|
||||
});
|
||||
}
|
||||
toast.success(
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Save } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { openclawApi } from "@/lib/api/openclaw";
|
||||
import {
|
||||
useOpenClawAgentsDefaults,
|
||||
useSaveOpenClawAgentsDefaults,
|
||||
} from "@/hooks/useOpenClaw";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
@@ -10,11 +14,11 @@ import type { OpenClawAgentsDefaults } from "@/types";
|
||||
|
||||
const AgentsDefaultsPanel: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const { data: agentsData, isLoading } = useOpenClawAgentsDefaults();
|
||||
const saveAgentsMutation = useSaveOpenClawAgentsDefaults();
|
||||
const [defaults, setDefaults] = useState<OpenClawAgentsDefaults | null>(null);
|
||||
const [primaryModel, setPrimaryModel] = useState("");
|
||||
const [fallbacks, setFallbacks] = useState("");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
// Extra known fields from agents.defaults
|
||||
const [workspace, setWorkspace] = useState("");
|
||||
@@ -22,38 +26,25 @@ const AgentsDefaultsPanel: React.FC = () => {
|
||||
const [contextTokens, setContextTokens] = useState("");
|
||||
const [maxConcurrent, setMaxConcurrent] = useState("");
|
||||
|
||||
const loadDefaults = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await openclawApi.getAgentsDefaults();
|
||||
setDefaults(data);
|
||||
|
||||
if (data) {
|
||||
setPrimaryModel(data.model?.primary ?? "");
|
||||
setFallbacks((data.model?.fallbacks ?? []).join(", "));
|
||||
|
||||
// Extract known extra fields
|
||||
setWorkspace(String(data.workspace ?? ""));
|
||||
setTimeout_(String(data.timeout ?? ""));
|
||||
setContextTokens(String(data.contextTokens ?? ""));
|
||||
setMaxConcurrent(String(data.maxConcurrent ?? ""));
|
||||
}
|
||||
} catch (err) {
|
||||
toast.error(t("openclaw.agents.loadFailed"));
|
||||
console.error("Failed to load agents defaults:", err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [t]);
|
||||
|
||||
useEffect(() => {
|
||||
void loadDefaults();
|
||||
}, [loadDefaults]);
|
||||
// agentsData is undefined while loading, null when config section is absent
|
||||
if (agentsData === undefined) return;
|
||||
setDefaults(agentsData);
|
||||
|
||||
if (agentsData) {
|
||||
setPrimaryModel(agentsData.model?.primary ?? "");
|
||||
setFallbacks((agentsData.model?.fallbacks ?? []).join(", "));
|
||||
|
||||
// Extract known extra fields
|
||||
setWorkspace(String(agentsData.workspace ?? ""));
|
||||
setTimeout_(String(agentsData.timeout ?? ""));
|
||||
setContextTokens(String(agentsData.contextTokens ?? ""));
|
||||
setMaxConcurrent(String(agentsData.maxConcurrent ?? ""));
|
||||
}
|
||||
}, [agentsData]);
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
setSaving(true);
|
||||
|
||||
// Preserve all unknown fields from original data
|
||||
const updated: OpenClawAgentsDefaults = { ...defaults };
|
||||
|
||||
@@ -94,18 +85,17 @@ const AgentsDefaultsPanel: React.FC = () => {
|
||||
if (concNum !== undefined) updated.maxConcurrent = concNum;
|
||||
else delete updated.maxConcurrent;
|
||||
|
||||
await openclawApi.setAgentsDefaults(updated);
|
||||
await saveAgentsMutation.mutateAsync(updated);
|
||||
toast.success(t("openclaw.agents.saveSuccess"));
|
||||
await loadDefaults();
|
||||
} catch (err) {
|
||||
toast.error(t("openclaw.agents.saveFailed"));
|
||||
console.error("Failed to save agents defaults:", err);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
} catch (error) {
|
||||
const detail = extractErrorMessage(error);
|
||||
toast.error(t("openclaw.agents.saveFailed"), {
|
||||
description: detail || undefined,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="px-6 pt-4 pb-8 flex items-center justify-center min-h-[200px]">
|
||||
<div className="text-sm text-muted-foreground">
|
||||
@@ -222,9 +212,13 @@ const AgentsDefaultsPanel: React.FC = () => {
|
||||
|
||||
{/* Save button */}
|
||||
<div className="flex justify-end">
|
||||
<Button size="sm" onClick={handleSave} disabled={saving}>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleSave}
|
||||
disabled={saveAgentsMutation.isPending}
|
||||
>
|
||||
<Save className="w-4 h-4 mr-1" />
|
||||
{saving ? t("common.saving") : t("common.save")}
|
||||
{saveAgentsMutation.isPending ? t("common.saving") : t("common.save")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Plus, Trash2, Save, Eye, EyeOff } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { openclawApi } from "@/lib/api/openclaw";
|
||||
import { useOpenClawEnv, useSaveOpenClawEnv } from "@/hooks/useOpenClaw";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import type { OpenClawEnvConfig } from "@/types";
|
||||
@@ -15,35 +16,23 @@ interface EnvEntry {
|
||||
|
||||
const EnvPanel: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const { data: envData, isLoading } = useOpenClawEnv();
|
||||
const saveEnvMutation = useSaveOpenClawEnv();
|
||||
const [entries, setEntries] = useState<EnvEntry[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [visibleKeys, setVisibleKeys] = useState<Set<string>>(new Set());
|
||||
|
||||
const loadEnv = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const env = await openclawApi.getEnv();
|
||||
const items: EnvEntry[] = Object.entries(env).map(([key, value]) => ({
|
||||
useEffect(() => {
|
||||
if (envData) {
|
||||
const items: EnvEntry[] = Object.entries(envData).map(([key, value]) => ({
|
||||
key,
|
||||
value: String(value ?? ""),
|
||||
}));
|
||||
setEntries(items.length > 0 ? items : []);
|
||||
} catch (err) {
|
||||
toast.error(t("openclaw.env.loadFailed"));
|
||||
console.error("Failed to load env config:", err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [t]);
|
||||
|
||||
useEffect(() => {
|
||||
void loadEnv();
|
||||
}, [loadEnv]);
|
||||
}, [envData]);
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
setSaving(true);
|
||||
const env: OpenClawEnvConfig = {};
|
||||
for (const entry of entries) {
|
||||
const trimmedKey = entry.key.trim();
|
||||
@@ -51,15 +40,13 @@ const EnvPanel: React.FC = () => {
|
||||
env[trimmedKey] = entry.value;
|
||||
}
|
||||
}
|
||||
await openclawApi.setEnv(env);
|
||||
await saveEnvMutation.mutateAsync(env);
|
||||
toast.success(t("openclaw.env.saveSuccess"));
|
||||
// Reload to normalize
|
||||
await loadEnv();
|
||||
} catch (err) {
|
||||
toast.error(t("openclaw.env.saveFailed"));
|
||||
console.error("Failed to save env config:", err);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
} catch (error) {
|
||||
const detail = extractErrorMessage(error);
|
||||
toast.error(t("openclaw.env.saveFailed"), {
|
||||
description: detail || undefined,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -93,7 +80,7 @@ const EnvPanel: React.FC = () => {
|
||||
|
||||
const isApiKey = (key: string) => /key|token|secret|password/i.test(key);
|
||||
|
||||
if (loading) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="px-6 pt-4 pb-8 flex items-center justify-center min-h-[200px]">
|
||||
<div className="text-sm text-muted-foreground">
|
||||
@@ -168,9 +155,13 @@ const EnvPanel: React.FC = () => {
|
||||
{t("openclaw.env.add")}
|
||||
</Button>
|
||||
<div className="flex-1" />
|
||||
<Button size="sm" onClick={handleSave} disabled={saving}>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleSave}
|
||||
disabled={saveEnvMutation.isPending}
|
||||
>
|
||||
<Save className="w-4 h-4 mr-1" />
|
||||
{saving ? t("common.saving") : t("common.save")}
|
||||
{saveEnvMutation.isPending ? t("common.saving") : t("common.save")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Plus, Trash2, Save } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { openclawApi } from "@/lib/api/openclaw";
|
||||
import { useOpenClawTools, useSaveOpenClawTools } from "@/hooks/useOpenClaw";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
@@ -19,34 +20,22 @@ const PROFILE_OPTIONS = ["default", "strict", "permissive", "custom"];
|
||||
|
||||
const ToolsPanel: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const { data: toolsData, isLoading } = useOpenClawTools();
|
||||
const saveToolsMutation = useSaveOpenClawTools();
|
||||
const [config, setConfig] = useState<OpenClawToolsConfig>({});
|
||||
const [allowList, setAllowList] = useState<string[]>([]);
|
||||
const [denyList, setDenyList] = useState<string[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
const loadTools = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const tools = await openclawApi.getTools();
|
||||
setConfig(tools);
|
||||
setAllowList(tools.allow ?? []);
|
||||
setDenyList(tools.deny ?? []);
|
||||
} catch (err) {
|
||||
toast.error(t("openclaw.tools.loadFailed"));
|
||||
console.error("Failed to load tools config:", err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [t]);
|
||||
|
||||
useEffect(() => {
|
||||
void loadTools();
|
||||
}, [loadTools]);
|
||||
if (toolsData) {
|
||||
setConfig(toolsData);
|
||||
setAllowList(toolsData.allow ?? []);
|
||||
setDenyList(toolsData.deny ?? []);
|
||||
}
|
||||
}, [toolsData]);
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
setSaving(true);
|
||||
const { profile, allow, deny, ...other } = config;
|
||||
const newConfig: OpenClawToolsConfig = {
|
||||
...other,
|
||||
@@ -54,14 +43,13 @@ const ToolsPanel: React.FC = () => {
|
||||
allow: allowList.filter((s) => s.trim()),
|
||||
deny: denyList.filter((s) => s.trim()),
|
||||
};
|
||||
await openclawApi.setTools(newConfig);
|
||||
await saveToolsMutation.mutateAsync(newConfig);
|
||||
toast.success(t("openclaw.tools.saveSuccess"));
|
||||
await loadTools();
|
||||
} catch (err) {
|
||||
toast.error(t("openclaw.tools.saveFailed"));
|
||||
console.error("Failed to save tools config:", err);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
} catch (error) {
|
||||
const detail = extractErrorMessage(error);
|
||||
toast.error(t("openclaw.tools.saveFailed"), {
|
||||
description: detail || undefined,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -82,7 +70,7 @@ const ToolsPanel: React.FC = () => {
|
||||
setList(list.filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="px-6 pt-4 pb-8 flex items-center justify-center min-h-[200px]">
|
||||
<div className="text-sm text-muted-foreground">
|
||||
@@ -192,9 +180,13 @@ const ToolsPanel: React.FC = () => {
|
||||
|
||||
{/* Save button */}
|
||||
<div className="flex justify-end">
|
||||
<Button size="sm" onClick={handleSave} disabled={saving}>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleSave}
|
||||
disabled={saveToolsMutation.isPending}
|
||||
>
|
||||
<Save className="w-4 h-4 mr-1" />
|
||||
{saving ? t("common.saving") : t("common.save")}
|
||||
{saveToolsMutation.isPending ? t("common.saving") : t("common.save")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,8 +19,12 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import type { Provider } from "@/types";
|
||||
import type { AppId } from "@/lib/api";
|
||||
import { providersApi } from "@/lib/api/providers";
|
||||
import { openclawApi } from "@/lib/api/openclaw";
|
||||
import { useDragSort } from "@/hooks/useDragSort";
|
||||
import {
|
||||
useOpenClawLiveProviderIds,
|
||||
useOpenClawDefaultModel,
|
||||
} from "@/hooks/useOpenClaw";
|
||||
// import { useStreamCheck } from "@/hooks/useStreamCheck"; // 测试功能已隐藏
|
||||
import { ProviderCard } from "@/components/providers/ProviderCard";
|
||||
import { ProviderEmptyState } from "@/components/providers/ProviderEmptyState";
|
||||
import {
|
||||
@@ -88,11 +92,9 @@ export function ProviderList({
|
||||
});
|
||||
|
||||
// OpenClaw: 查询 live 配置中的供应商 ID 列表,用于判断 isInConfig
|
||||
const { data: openclawLiveIds } = useQuery({
|
||||
queryKey: ["openclawLiveProviderIds"],
|
||||
queryFn: () => providersApi.getOpenClawLiveProviderIds(),
|
||||
enabled: appId === "openclaw",
|
||||
});
|
||||
const { data: openclawLiveIds } = useOpenClawLiveProviderIds(
|
||||
appId === "openclaw",
|
||||
);
|
||||
|
||||
// 判断供应商是否已添加到配置(累加模式应用:OpenCode/OpenClaw)
|
||||
const isProviderInConfig = useCallback(
|
||||
@@ -109,11 +111,9 @@ export function ProviderList({
|
||||
);
|
||||
|
||||
// OpenClaw: query default model to determine which provider is default
|
||||
const { data: openclawDefaultModel } = useQuery({
|
||||
queryKey: ["openclawDefaultModel"],
|
||||
queryFn: () => openclawApi.getDefaultModel(),
|
||||
enabled: appId === "openclaw",
|
||||
});
|
||||
const { data: openclawDefaultModel } = useOpenClawDefaultModel(
|
||||
appId === "openclaw",
|
||||
);
|
||||
|
||||
const isProviderDefaultModel = useCallback(
|
||||
(providerId: string): boolean => {
|
||||
|
||||
128
src/hooks/useOpenClaw.ts
Normal file
128
src/hooks/useOpenClaw.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { openclawApi } from "@/lib/api/openclaw";
|
||||
import { providersApi } from "@/lib/api/providers";
|
||||
import type {
|
||||
OpenClawEnvConfig,
|
||||
OpenClawToolsConfig,
|
||||
OpenClawAgentsDefaults,
|
||||
} from "@/types";
|
||||
|
||||
/**
|
||||
* Centralized query keys for all OpenClaw-related queries.
|
||||
* Import this from any file that needs to invalidate OpenClaw caches.
|
||||
*/
|
||||
export const openclawKeys = {
|
||||
all: ["openclaw"] as const,
|
||||
liveProviderIds: ["openclaw", "liveProviderIds"] as const,
|
||||
defaultModel: ["openclaw", "defaultModel"] as const,
|
||||
env: ["openclaw", "env"] as const,
|
||||
tools: ["openclaw", "tools"] as const,
|
||||
agentsDefaults: ["openclaw", "agentsDefaults"] as const,
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Query hooks
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Query live provider IDs from openclaw.json config.
|
||||
* Used by ProviderList to show "In Config" badge.
|
||||
*/
|
||||
export function useOpenClawLiveProviderIds(enabled: boolean) {
|
||||
return useQuery({
|
||||
queryKey: openclawKeys.liveProviderIds,
|
||||
queryFn: () => providersApi.getOpenClawLiveProviderIds(),
|
||||
enabled,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the default model from agents.defaults.model.
|
||||
* Used by ProviderList to show which provider is the default.
|
||||
*/
|
||||
export function useOpenClawDefaultModel(enabled: boolean) {
|
||||
return useQuery({
|
||||
queryKey: openclawKeys.defaultModel,
|
||||
queryFn: () => openclawApi.getDefaultModel(),
|
||||
enabled,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Query env section of openclaw.json.
|
||||
*/
|
||||
export function useOpenClawEnv() {
|
||||
return useQuery({
|
||||
queryKey: openclawKeys.env,
|
||||
queryFn: () => openclawApi.getEnv(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Query tools section of openclaw.json.
|
||||
*/
|
||||
export function useOpenClawTools() {
|
||||
return useQuery({
|
||||
queryKey: openclawKeys.tools,
|
||||
queryFn: () => openclawApi.getTools(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Query agents.defaults section of openclaw.json.
|
||||
*/
|
||||
export function useOpenClawAgentsDefaults() {
|
||||
return useQuery({
|
||||
queryKey: openclawKeys.agentsDefaults,
|
||||
queryFn: () => openclawApi.getAgentsDefaults(),
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Mutation hooks
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Save env config. Invalidates env query on success.
|
||||
* Toast notifications are handled by the component.
|
||||
*/
|
||||
export function useSaveOpenClawEnv() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (env: OpenClawEnvConfig) => openclawApi.setEnv(env),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: openclawKeys.env });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Save tools config. Invalidates tools query on success.
|
||||
* Toast notifications are handled by the component.
|
||||
*/
|
||||
export function useSaveOpenClawTools() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (tools: OpenClawToolsConfig) => openclawApi.setTools(tools),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: openclawKeys.tools });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Save agents.defaults config. Invalidates both agentsDefaults and defaultModel
|
||||
* queries on success (since changing agents.defaults may affect the default model).
|
||||
* Toast notifications are handled by the component.
|
||||
*/
|
||||
export function useSaveOpenClawAgentsDefaults() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (defaults: OpenClawAgentsDefaults) =>
|
||||
openclawApi.setAgentsDefaults(defaults),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: openclawKeys.agentsDefaults });
|
||||
queryClient.invalidateQueries({ queryKey: openclawKeys.defaultModel });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
useSwitchProviderMutation,
|
||||
} from "@/lib/query";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { openclawKeys } from "@/hooks/useOpenClaw";
|
||||
|
||||
/**
|
||||
* Hook for managing provider actions (add, update, delete, switch)
|
||||
@@ -244,7 +245,7 @@ export function useProviderActions(activeApp: AppId) {
|
||||
try {
|
||||
await openclawApi.setDefaultModel(model);
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["openclawDefaultModel"],
|
||||
queryKey: openclawKeys.defaultModel,
|
||||
});
|
||||
toast.success(
|
||||
t("notifications.openclawDefaultModelSet", {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { providersApi, settingsApi, type AppId } from "@/lib/api";
|
||||
import type { Provider, Settings } from "@/types";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { generateUUID } from "@/utils/uuid";
|
||||
import { openclawKeys } from "@/hooks/useOpenClaw";
|
||||
|
||||
export const useAddProviderMutation = (appId: AppId) => {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -185,10 +186,10 @@ export const useSwitchProviderMutation = (appId: AppId) => {
|
||||
}
|
||||
if (appId === "openclaw") {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["openclawLiveProviderIds"],
|
||||
queryKey: openclawKeys.liveProviderIds,
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["openclawDefaultModel"],
|
||||
queryKey: openclawKeys.defaultModel,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user