mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-05-20 20:33:22 +08:00
57713dd336
Display an info toast when switching to a provider that uses OpenAI Chat format (apiFormat === "openai_chat"), reminding users to enable the proxy service. Move toast logic from mutation to useProviderActions for better control over notification content based on provider properties.
213 lines
5.9 KiB
TypeScript
213 lines
5.9 KiB
TypeScript
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { useTranslation } from "react-i18next";
|
|
import { toast } from "sonner";
|
|
import { providersApi, settingsApi, type AppId } from "@/lib/api";
|
|
import type { Provider, Settings } from "@/types";
|
|
import { extractErrorMessage } from "@/utils/errorUtils";
|
|
import { generateUUID } from "@/utils/uuid";
|
|
|
|
export const useAddProviderMutation = (appId: AppId) => {
|
|
const queryClient = useQueryClient();
|
|
const { t } = useTranslation();
|
|
|
|
return useMutation({
|
|
mutationFn: async (
|
|
providerInput: Omit<Provider, "id"> & { providerKey?: string },
|
|
) => {
|
|
let id: string;
|
|
|
|
if (appId === "opencode") {
|
|
// OpenCode: use user-provided providerKey as ID
|
|
if (!providerInput.providerKey) {
|
|
throw new Error("Provider key is required for OpenCode");
|
|
}
|
|
id = providerInput.providerKey;
|
|
} else {
|
|
// Other apps: use random UUID
|
|
id = generateUUID();
|
|
}
|
|
|
|
const newProvider: Provider = {
|
|
...providerInput,
|
|
id,
|
|
createdAt: Date.now(),
|
|
};
|
|
// Remove providerKey from the provider object before saving
|
|
delete (newProvider as any).providerKey;
|
|
|
|
await providersApi.add(newProvider, appId);
|
|
return newProvider;
|
|
},
|
|
onSuccess: async () => {
|
|
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
|
|
|
// 更新托盘菜单(失败不影响主操作)
|
|
try {
|
|
await providersApi.updateTrayMenu();
|
|
} catch (trayError) {
|
|
console.error(
|
|
"Failed to update tray menu after adding provider",
|
|
trayError,
|
|
);
|
|
}
|
|
|
|
toast.success(
|
|
t("notifications.providerAdded", {
|
|
defaultValue: "供应商已添加",
|
|
}),
|
|
{
|
|
closeButton: true,
|
|
},
|
|
);
|
|
},
|
|
onError: (error: Error) => {
|
|
toast.error(
|
|
t("notifications.addFailed", {
|
|
defaultValue: "添加供应商失败: {{error}}",
|
|
error: error.message,
|
|
}),
|
|
);
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useUpdateProviderMutation = (appId: AppId) => {
|
|
const queryClient = useQueryClient();
|
|
const { t } = useTranslation();
|
|
|
|
return useMutation({
|
|
mutationFn: async (provider: Provider) => {
|
|
await providersApi.update(provider, appId);
|
|
return provider;
|
|
},
|
|
onSuccess: async () => {
|
|
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
|
toast.success(
|
|
t("notifications.updateSuccess", {
|
|
defaultValue: "供应商更新成功",
|
|
}),
|
|
{
|
|
closeButton: true,
|
|
},
|
|
);
|
|
},
|
|
onError: (error: Error) => {
|
|
toast.error(
|
|
t("notifications.updateFailed", {
|
|
defaultValue: "更新供应商失败: {{error}}",
|
|
error: error.message,
|
|
}),
|
|
);
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useDeleteProviderMutation = (appId: AppId) => {
|
|
const queryClient = useQueryClient();
|
|
const { t } = useTranslation();
|
|
|
|
return useMutation({
|
|
mutationFn: async (providerId: string) => {
|
|
await providersApi.delete(providerId, appId);
|
|
},
|
|
onSuccess: async () => {
|
|
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
|
|
|
// 更新托盘菜单(失败不影响主操作)
|
|
try {
|
|
await providersApi.updateTrayMenu();
|
|
} catch (trayError) {
|
|
console.error(
|
|
"Failed to update tray menu after deleting provider",
|
|
trayError,
|
|
);
|
|
}
|
|
|
|
toast.success(
|
|
t("notifications.deleteSuccess", {
|
|
defaultValue: "供应商已删除",
|
|
}),
|
|
{
|
|
closeButton: true,
|
|
},
|
|
);
|
|
},
|
|
onError: (error: Error) => {
|
|
toast.error(
|
|
t("notifications.deleteFailed", {
|
|
defaultValue: "删除供应商失败: {{error}}",
|
|
error: error.message,
|
|
}),
|
|
);
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useSwitchProviderMutation = (appId: AppId) => {
|
|
const queryClient = useQueryClient();
|
|
const { t } = useTranslation();
|
|
|
|
return useMutation({
|
|
mutationFn: async (providerId: string) => {
|
|
return await providersApi.switch(providerId, appId);
|
|
},
|
|
onSuccess: async () => {
|
|
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
|
|
|
// OpenCode: also invalidate live provider IDs cache to update button state
|
|
if (appId === "opencode") {
|
|
await queryClient.invalidateQueries({
|
|
queryKey: ["opencodeLiveProviderIds"],
|
|
});
|
|
}
|
|
|
|
// 更新托盘菜单(失败不影响主操作)
|
|
try {
|
|
await providersApi.updateTrayMenu();
|
|
} catch (trayError) {
|
|
console.error(
|
|
"Failed to update tray menu after switching provider",
|
|
trayError,
|
|
);
|
|
}
|
|
|
|
// Note: Success toast is handled by useProviderActions.switchProvider
|
|
// to allow customization based on provider properties (e.g., apiFormat)
|
|
},
|
|
onError: (error: Error) => {
|
|
const detail = extractErrorMessage(error) || t("common.unknown");
|
|
|
|
// 标题与详情分离,便于扫描 + 一键复制
|
|
toast.error(
|
|
t("notifications.switchFailedTitle", { defaultValue: "切换失败" }),
|
|
{
|
|
description: t("notifications.switchFailed", {
|
|
defaultValue: "切换失败:{{error}}",
|
|
error: detail,
|
|
}),
|
|
duration: 6000,
|
|
action: {
|
|
label: t("common.copy", { defaultValue: "复制" }),
|
|
onClick: () => {
|
|
navigator.clipboard?.writeText(detail).catch(() => undefined);
|
|
},
|
|
},
|
|
},
|
|
);
|
|
},
|
|
});
|
|
};
|
|
|
|
export const useSaveSettingsMutation = () => {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async (settings: Settings) => {
|
|
await settingsApi.save(settings);
|
|
},
|
|
onSuccess: async () => {
|
|
await queryClient.invalidateQueries({ queryKey: ["settings"] });
|
|
},
|
|
});
|
|
};
|