refactor: remove backup path display from OpenClaw save toasts

Backup paths are internal implementation details not actionable by users.
Simplify toast notifications to show only success/failure messages.
This commit is contained in:
Jason
2026-03-09 15:00:30 +08:00
parent 99ef870077
commit 44096b0e44
5 changed files with 51 additions and 37 deletions
@@ -169,15 +169,8 @@ const AgentsDefaultsPanel: React.FC = () => {
if (concNum !== undefined) updated.maxConcurrent = concNum;
else delete updated.maxConcurrent;
const outcome = await saveAgentsMutation.mutateAsync(updated);
toast.success(t("openclaw.agents.saveSuccess"), {
description: outcome.backupPath
? t("openclaw.backupCreated", {
path: outcome.backupPath,
defaultValue: "Backup created: {{path}}",
})
: undefined,
});
await saveAgentsMutation.mutateAsync(updated);
toast.success(t("openclaw.agents.saveSuccess"));
} catch (error) {
const detail = extractErrorMessage(error);
toast.error(t("openclaw.agents.saveFailed"), {
+2 -9
View File
@@ -41,15 +41,8 @@ const EnvPanel: React.FC = () => {
const handleSave = async () => {
try {
const env = parseOpenClawEnvEditorValue(editorValue);
const outcome = await saveEnvMutation.mutateAsync(env);
toast.success(t("openclaw.env.saveSuccess"), {
description: outcome.backupPath
? t("openclaw.backupCreated", {
path: outcome.backupPath,
defaultValue: "Backup created: {{path}}",
})
: undefined,
});
await saveEnvMutation.mutateAsync(env);
toast.success(t("openclaw.env.saveSuccess"));
} catch (error) {
const detail = extractErrorMessage(error);
let description = detail || undefined;
+2 -9
View File
@@ -85,15 +85,8 @@ const ToolsPanel: React.FC = () => {
deny: denyList.map((item) => item.value).filter((s) => s.trim()),
};
const outcome = await saveToolsMutation.mutateAsync(newConfig);
toast.success(t("openclaw.tools.saveSuccess"), {
description: outcome.backupPath
? t("openclaw.backupCreated", {
path: outcome.backupPath,
defaultValue: "Backup created: {{path}}",
})
: undefined,
});
await saveToolsMutation.mutateAsync(newConfig);
toast.success(t("openclaw.tools.saveSuccess"));
} catch (error) {
const detail = extractErrorMessage(error);
toast.error(t("openclaw.tools.saveFailed"), {
+2 -10
View File
@@ -261,7 +261,7 @@ export function useProviderActions(activeApp: AppId) {
};
try {
const outcome = await openclawApi.setDefaultModel(model);
await openclawApi.setDefaultModel(model);
await queryClient.invalidateQueries({
queryKey: openclawKeys.defaultModel,
});
@@ -272,15 +272,7 @@ export function useProviderActions(activeApp: AppId) {
t("notifications.openclawDefaultModelSet", {
defaultValue: "已设为默认模型",
}),
{
closeButton: true,
description: outcome.backupPath
? t("openclaw.backupCreated", {
path: outcome.backupPath,
defaultValue: "Backup created: {{path}}",
})
: undefined,
},
{ closeButton: true },
);
} catch (error) {
const detail =
+43
View File
@@ -53,6 +53,9 @@ const providersApiUpdateMock = vi.fn();
const providersApiUpdateTrayMenuMock = vi.fn();
const settingsApiGetMock = vi.fn();
const settingsApiApplyMock = vi.fn();
const openclawApiGetModelCatalogMock = vi.fn();
const openclawApiGetDefaultModelMock = vi.fn();
const openclawApiSetDefaultModelMock = vi.fn();
vi.mock("@/lib/api", () => ({
providersApi: {
@@ -65,6 +68,14 @@ vi.mock("@/lib/api", () => ({
applyClaudePluginConfig: (...args: unknown[]) =>
settingsApiApplyMock(...args),
},
openclawApi: {
getModelCatalog: (...args: unknown[]) =>
openclawApiGetModelCatalogMock(...args),
getDefaultModel: (...args: unknown[]) =>
openclawApiGetDefaultModelMock(...args),
setDefaultModel: (...args: unknown[]) =>
openclawApiSetDefaultModelMock(...args),
},
}));
interface WrapperProps {
@@ -100,6 +111,9 @@ beforeEach(() => {
providersApiUpdateTrayMenuMock.mockReset();
settingsApiGetMock.mockReset();
settingsApiApplyMock.mockReset();
openclawApiGetModelCatalogMock.mockReset();
openclawApiGetDefaultModelMock.mockReset();
openclawApiSetDefaultModelMock.mockReset();
toastSuccessMock.mockReset();
toastErrorMock.mockReset();
@@ -450,6 +464,35 @@ describe("useProviderActions", () => {
expect(result.current.isLoading).toBe(true);
});
it("does not show backup details when setting OpenClaw default model", async () => {
openclawApiSetDefaultModelMock.mockResolvedValueOnce({
backupPath: "/tmp/openclaw-backup.json5",
warnings: [],
});
const { wrapper } = createWrapper();
const provider = createProvider({
settingsConfig: {
models: [{ id: "gpt-4.1" }, { id: "gpt-4.1-mini" }],
},
});
const { result } = renderHook(() => useProviderActions("openclaw"), {
wrapper,
});
await act(async () => {
await result.current.setAsDefaultModel(provider);
});
expect(openclawApiSetDefaultModelMock).toHaveBeenCalledWith({
primary: "provider-1/gpt-4.1",
fallbacks: ["provider-1/gpt-4.1-mini"],
});
expect(toastSuccessMock).toHaveBeenCalledTimes(1);
expect(toastSuccessMock.mock.calls[0]?.[1]).toEqual({ closeButton: true });
});
});
it("clears loading flag when all mutations idle", () => {
addProviderMutation.isPending = false;