feat(auth-files): normalize OAuth excluded models handling and update related API methods

This commit is contained in:
Supra4E8C
2026-01-07 12:26:33 +08:00
parent ee99836285
commit f663b83ac8
4 changed files with 96 additions and 38 deletions

View File

@@ -68,7 +68,6 @@ const TYPE_COLORS: Record<string, TypeColorSet> = {
};
const OAUTH_PROVIDER_PRESETS = [
'gemini',
'gemini-cli',
'vertex',
'aistudio',
@@ -160,11 +159,11 @@ function resolveAuthFileStats(
return defaultStats;
}
export function AuthFilesPage() {
const { t } = useTranslation();
const { showNotification } = useNotificationStore();
const connectionStatus = useAuthStore((state) => state.connectionStatus);
const resolvedTheme: ResolvedTheme = useThemeStore((state) => state.resolvedTheme);
export function AuthFilesPage() {
const { t } = useTranslation();
const { showNotification } = useNotificationStore();
const connectionStatus = useAuthStore((state) => state.connectionStatus);
const resolvedTheme: ResolvedTheme = useThemeStore((state) => state.resolvedTheme);
const [files, setFiles] = useState<AuthFileItem[]>([]);
const [loading, setLoading] = useState(true);
@@ -215,6 +214,8 @@ export function AuthFilesPage() {
const disableControls = connectionStatus !== 'connected';
const normalizeProviderKey = (value: string) => value.trim().toLowerCase();
const handlePageSizeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.currentTarget.valueAsNumber;
if (!Number.isFinite(value)) return;
@@ -626,13 +627,14 @@ export function AuthFilesPage() {
};
// 检查模型是否被 OAuth 排除
const isModelExcluded = (modelId: string, providerType: string): boolean => {
const excludedModels = excluded[providerType] || [];
return excludedModels.some(pattern => {
if (pattern.includes('*')) {
// 支持通配符匹配
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$', 'i');
return regex.test(modelId);
const isModelExcluded = (modelId: string, providerType: string): boolean => {
const providerKey = normalizeProviderKey(providerType);
const excludedModels = excluded[providerKey] || excluded[providerType] || [];
return excludedModels.some(pattern => {
if (pattern.includes('*')) {
// 支持通配符匹配
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$', 'i');
return regex.test(modelId);
}
return pattern.toLowerCase() === modelId.toLowerCase();
});
@@ -655,11 +657,10 @@ export function AuthFilesPage() {
// OAuth 排除相关方法
const openExcludedModal = (provider?: string) => {
const normalizedProvider = (provider || '').trim();
const fallbackProvider = normalizedProvider || (filter !== 'all' ? String(filter) : '');
const lookupKey = fallbackProvider
? excludedProviderLookup.get(fallbackProvider.toLowerCase())
: undefined;
const normalizedProvider = normalizeProviderKey(provider || '');
const fallbackProvider =
normalizedProvider || (filter !== 'all' ? normalizeProviderKey(String(filter)) : '');
const lookupKey = fallbackProvider ? excludedProviderLookup.get(fallbackProvider) : undefined;
const models = lookupKey ? excluded[lookupKey] : [];
setExcludedForm({
provider: lookupKey || fallbackProvider,
@@ -669,7 +670,7 @@ export function AuthFilesPage() {
};
const saveExcludedModels = async () => {
const provider = excludedForm.provider.trim();
const provider = normalizeProviderKey(excludedForm.provider);
if (!provider) {
showNotification(t('oauth_excluded.provider_required'), 'error');
return;
@@ -679,13 +680,13 @@ export function AuthFilesPage() {
.map((item) => item.trim())
.filter(Boolean);
setSavingExcluded(true);
try {
if (models.length) {
await authFilesApi.saveOauthExcludedModels(provider, models);
} else {
await authFilesApi.deleteOauthExcludedEntry(provider);
}
await loadExcluded();
try {
if (models.length) {
await authFilesApi.saveOauthExcludedModels(provider, models);
} else {
await authFilesApi.deleteOauthExcludedEntry(provider);
}
await loadExcluded();
showNotification(t('oauth_excluded.save_success'), 'success');
setExcludedModalOpen(false);
} catch (err: unknown) {
@@ -697,14 +698,32 @@ export function AuthFilesPage() {
};
const deleteExcluded = async (provider: string) => {
if (!window.confirm(t('oauth_excluded.delete_confirm', { provider }))) return;
try {
await authFilesApi.deleteOauthExcludedEntry(provider);
await loadExcluded();
showNotification(t('oauth_excluded.delete_success'), 'success');
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : '';
showNotification(`${t('oauth_excluded.delete_failed')}: ${errorMessage}`, 'error');
const providerLabel = provider.trim() || provider;
if (!window.confirm(t('oauth_excluded.delete_confirm', { provider: providerLabel }))) return;
const providerKey = normalizeProviderKey(provider);
if (!providerKey) {
showNotification(t('oauth_excluded.provider_required'), 'error');
return;
}
try {
await authFilesApi.deleteOauthExcludedEntry(providerKey);
await loadExcluded();
showNotification(t('oauth_excluded.delete_success'), 'success');
} catch (err: unknown) {
try {
const current = await authFilesApi.getOauthExcludedModels();
const next: Record<string, string[]> = {};
Object.entries(current).forEach(([key, models]) => {
if (normalizeProviderKey(key) === providerKey) return;
next[key] = models;
});
await authFilesApi.replaceOauthExcludedModels(next);
await loadExcluded();
showNotification(t('oauth_excluded.delete_success'), 'success');
} catch (fallbackErr: unknown) {
const errorMessage = fallbackErr instanceof Error ? fallbackErr.message : err instanceof Error ? err.message : '';
showNotification(`${t('oauth_excluded.delete_failed')}: ${errorMessage}`, 'error');
}
}
};