feat: add provider duplicate functionality in edit mode

Add a duplicate button next to the drag handle in edit mode that allows users to quickly copy existing provider configurations.

- Add Copy icon button in ProviderCard next to drag handle
- Implement handleDuplicateProvider in App.tsx with deep cloning
- Copy all provider settings (settingsConfig, websiteUrl, category, meta)
- Auto-generate new ID and timestamp, omit sortIndex for natural sorting
- Append " copy" to duplicated provider name
- Add i18n support (zh: "复制", en: "Duplicate")
- Wire onDuplicate callback through ProviderList to ProviderCard

The duplicated provider will appear below the original provider in the list, sorted by creation time.
This commit is contained in:
Jason
2025-10-24 11:56:18 +08:00
parent 07787a2ee1
commit fb0dc5b186
5 changed files with 48 additions and 5 deletions

View File

@@ -59,7 +59,7 @@ function App() {
if (event.appType === activeApp) {
await refetch();
}
}
},
);
} catch (error) {
console.error("[App] Failed to subscribe provider switch event", error);
@@ -99,6 +99,22 @@ function App() {
setConfirmDelete(null);
};
// 复制供应商
const handleDuplicateProvider = async (provider: Provider) => {
const duplicatedProvider: Omit<Provider, "id" | "createdAt"> = {
name: `${provider.name} copy`,
settingsConfig: JSON.parse(JSON.stringify(provider.settingsConfig)), // 深拷贝
websiteUrl: provider.websiteUrl,
category: provider.category,
meta: provider.meta
? JSON.parse(JSON.stringify(provider.meta))
: undefined, // 深拷贝
// sortIndex 不复制,让它按 createdAt 自然排序
};
await addProvider(duplicatedProvider);
};
// 导入配置成功后刷新
const handleImportSuccess = async () => {
await refetch();
@@ -136,7 +152,7 @@ function App() {
size="icon"
onClick={() => setIsEditMode(!isEditMode)}
title={t(
isEditMode ? "header.exitEditMode" : "header.enterEditMode"
isEditMode ? "header.exitEditMode" : "header.enterEditMode",
)}
className={
isEditMode
@@ -177,6 +193,7 @@ function App() {
onSwitch={switchProvider}
onEdit={setEditingProvider}
onDelete={setConfirmDelete}
onDuplicate={handleDuplicateProvider}
onConfigureUsage={setUsageProvider}
onOpenWebsite={handleOpenWebsite}
onCreate={() => setIsAddOpen(true)}