mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-19 03:00:49 +08:00
fix(drag-and-drop): add data transfer for source and alias during drag events
fix(i18n): update view mode labels in Chinese localization fix(auth-files): set fork to true in empty mapping entry and improve error handling in save/delete operations
This commit is contained in:
@@ -274,6 +274,7 @@ export const ModelMappingDiagram = forwardRef<ModelMappingDiagramRef, ModelMappi
|
|||||||
// 1. Source -> Alias
|
// 1. Source -> Alias
|
||||||
const handleDragStart = (e: DragEvent, source: SourceNode) => {
|
const handleDragStart = (e: DragEvent, source: SourceNode) => {
|
||||||
setDraggedSource(source);
|
setDraggedSource(source);
|
||||||
|
e.dataTransfer.setData('text/plain', source.id);
|
||||||
e.dataTransfer.effectAllowed = 'link';
|
e.dataTransfer.effectAllowed = 'link';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -300,6 +301,7 @@ export const ModelMappingDiagram = forwardRef<ModelMappingDiagramRef, ModelMappi
|
|||||||
// 2. Alias -> Source
|
// 2. Alias -> Source
|
||||||
const handleDragStartAlias = (e: DragEvent, alias: string) => {
|
const handleDragStartAlias = (e: DragEvent, alias: string) => {
|
||||||
setDraggedAlias(alias);
|
setDraggedAlias(alias);
|
||||||
|
e.dataTransfer.setData('text/plain', alias);
|
||||||
e.dataTransfer.effectAllowed = 'link';
|
e.dataTransfer.effectAllowed = 'link';
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -429,7 +431,7 @@ export const ModelMappingDiagram = forwardRef<ModelMappingDiagramRef, ModelMappi
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${styles.container} ${className}`}
|
className={[styles.container, className].filter(Boolean).join(' ')}
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
onContextMenu={(e) => {
|
onContextMenu={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -578,8 +578,8 @@
|
|||||||
"diagram_settings_source_title": "源模型设置",
|
"diagram_settings_source_title": "源模型设置",
|
||||||
"diagram_settings_empty": "该别名暂无映射。",
|
"diagram_settings_empty": "该别名暂无映射。",
|
||||||
"view_mode": "视图模式",
|
"view_mode": "视图模式",
|
||||||
"view_mode_diagram": "Diagram",
|
"view_mode_diagram": "概览",
|
||||||
"view_mode_list": "List",
|
"view_mode_list": "管理",
|
||||||
"provider_required": "请先填写提供商名称",
|
"provider_required": "请先填写提供商名称",
|
||||||
"upgrade_required": "当前 CPA 版本不支持模型别名功能,请升级 CPA 版本",
|
"upgrade_required": "当前 CPA 版本不支持模型别名功能,请升级 CPA 版本",
|
||||||
"upgrade_required_title": "需要升级 CPA 版本",
|
"upgrade_required_title": "需要升级 CPA 版本",
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const buildEmptyMappingEntry = (): OAuthModelMappingFormEntry => ({
|
|||||||
id: generateId(),
|
id: generateId(),
|
||||||
name: '',
|
name: '',
|
||||||
alias: '',
|
alias: '',
|
||||||
fork: false,
|
fork: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const normalizeMappingEntries = (
|
const normalizeMappingEntries = (
|
||||||
|
|||||||
@@ -271,6 +271,8 @@ export function AuthFilesPage() {
|
|||||||
}, [files, modelAlias]);
|
}, [files, modelAlias]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (viewMode !== 'diagram') return;
|
||||||
|
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
||||||
const loadAllModels = async () => {
|
const loadAllModels = async () => {
|
||||||
@@ -307,7 +309,7 @@ export function AuthFilesPage() {
|
|||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [providerList]);
|
}, [providerList, viewMode]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1200,8 +1202,11 @@ export function AuthFilesPage() {
|
|||||||
|
|
||||||
if (providersToUpdate.length === 0) return;
|
if (providersToUpdate.length === 0) return;
|
||||||
|
|
||||||
|
let hadFailure = false;
|
||||||
|
let failureMessage = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Promise.all(
|
const results = await Promise.allSettled(
|
||||||
providersToUpdate.map(([provider, mappings]) => {
|
providersToUpdate.map(([provider, mappings]) => {
|
||||||
const nextMappings = mappings.map((m) =>
|
const nextMappings = mappings.map((m) =>
|
||||||
(m.alias ?? '').trim().toLowerCase() === oldKey ? { ...m, alias: newTrim } : m
|
(m.alias ?? '').trim().toLowerCase() === oldKey ? { ...m, alias: newTrim } : m
|
||||||
@@ -1209,11 +1214,29 @@ export function AuthFilesPage() {
|
|||||||
return authFilesApi.saveOauthModelAlias(provider, nextMappings);
|
return authFilesApi.saveOauthModelAlias(provider, nextMappings);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const failures = results.filter(
|
||||||
|
(result): result is PromiseRejectedResult => result.status === 'rejected'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (failures.length > 0) {
|
||||||
|
hadFailure = true;
|
||||||
|
const reason = failures[0].reason;
|
||||||
|
failureMessage = reason instanceof Error ? reason.message : String(reason ?? '');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
await loadModelAlias();
|
await loadModelAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hadFailure) {
|
||||||
|
showNotification(
|
||||||
|
failureMessage
|
||||||
|
? `${t('oauth_model_alias.save_failed')}: ${failureMessage}`
|
||||||
|
: t('oauth_model_alias.save_failed'),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
showNotification(t('oauth_model_alias.save_success'), 'success');
|
showNotification(t('oauth_model_alias.save_success'), 'success');
|
||||||
} catch (err: unknown) {
|
|
||||||
const errorMessage = err instanceof Error ? err.message : '';
|
|
||||||
showNotification(`${t('oauth_model_alias.save_failed')}: ${errorMessage}`, 'error');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1239,8 +1262,11 @@ export function AuthFilesPage() {
|
|||||||
variant: 'danger',
|
variant: 'danger',
|
||||||
confirmText: t('common.confirm'),
|
confirmText: t('common.confirm'),
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
|
let hadFailure = false;
|
||||||
|
let failureMessage = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Promise.all(
|
const results = await Promise.allSettled(
|
||||||
providersToUpdate.map(([provider, mappings]) => {
|
providersToUpdate.map(([provider, mappings]) => {
|
||||||
const nextMappings = mappings.filter(
|
const nextMappings = mappings.filter(
|
||||||
(m) => (m.alias ?? '').trim().toLowerCase() !== aliasKey
|
(m) => (m.alias ?? '').trim().toLowerCase() !== aliasKey
|
||||||
@@ -1251,11 +1277,29 @@ export function AuthFilesPage() {
|
|||||||
return authFilesApi.saveOauthModelAlias(provider, nextMappings);
|
return authFilesApi.saveOauthModelAlias(provider, nextMappings);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const failures = results.filter(
|
||||||
|
(result): result is PromiseRejectedResult => result.status === 'rejected'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (failures.length > 0) {
|
||||||
|
hadFailure = true;
|
||||||
|
const reason = failures[0].reason;
|
||||||
|
failureMessage = reason instanceof Error ? reason.message : String(reason ?? '');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
await loadModelAlias();
|
await loadModelAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hadFailure) {
|
||||||
|
showNotification(
|
||||||
|
failureMessage
|
||||||
|
? `${t('oauth_model_alias.delete_failed')}: ${failureMessage}`
|
||||||
|
: t('oauth_model_alias.delete_failed'),
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
showNotification(t('oauth_model_alias.delete_success'), 'success');
|
showNotification(t('oauth_model_alias.delete_success'), 'success');
|
||||||
} catch (err: unknown) {
|
|
||||||
const errorMessage = err instanceof Error ? err.message : '';
|
|
||||||
showNotification(`${t('oauth_model_alias.delete_failed')}: ${errorMessage}`, 'error');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user