From a34abfc587c8fcc7d26863a91504c96ac756e3f9 Mon Sep 17 00:00:00 2001 From: lzt404 <2596933790@qq.com> Date: Tue, 1 Sep 2026 22:57:53 +0800 Subject: [PATCH] fix(ui): improve auth file and core install notifications - show auth file operation notices as auto-dismiss toasts - prevent duplicate core install completion notifications - close the install dialog automatically after successful installation - bump core version to 7.2.146 --- core-version.txt | 2 +- src/pages/AuthFileManagementPage.tsx | 31 ++++++++++++++++++++++------ src/pages/VersionManagementPage.tsx | 19 +++++++++++++++-- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/core-version.txt b/core-version.txt index c279578..c36f358 100644 --- a/core-version.txt +++ b/core-version.txt @@ -1 +1 @@ -7.2.145 +7.2.146 diff --git a/src/pages/AuthFileManagementPage.tsx b/src/pages/AuthFileManagementPage.tsx index 62c2a06..cf4e345 100644 --- a/src/pages/AuthFileManagementPage.tsx +++ b/src/pages/AuthFileManagementPage.tsx @@ -167,6 +167,16 @@ export function AuthFileManagementPage() { const quotas = useQuotaCache(); const fileInputRef = useRef(null); const oauthModelRequestRef = useRef(0); + const noticeTimerRef = useRef(null); + + const showNotice = useCallback((message: string) => { + if (noticeTimerRef.current !== null) window.clearTimeout(noticeTimerRef.current); + setNotice(message); + noticeTimerRef.current = window.setTimeout(() => { + setNotice(''); + noticeTimerRef.current = null; + }, 3600); + }, []); const loadFiles = useCallback(async () => { setLoading(true); @@ -256,7 +266,7 @@ export function AuthFileManagementPage() { models: excludedModels, }); } - setNotice(t('authFiles.models.updated', { provider: oauthModelProviderLabel })); + showNotice(t('authFiles.models.updated', { provider: oauthModelProviderLabel })); closeOauthModels(); } catch (requestError) { setOauthModelError(String(requestError)); @@ -302,6 +312,10 @@ export function AuthFileManagementPage() { void loadFiles(); }, [loadFiles]); + useEffect(() => () => { + if (noticeTimerRef.current !== null) window.clearTimeout(noticeTimerRef.current); + }, []); + const providers = useMemo( () => Array.from(new Set(files.map(providerName))).sort((left, right) => left.localeCompare(right)), [files], @@ -345,7 +359,7 @@ export function AuthFileManagementPage() { } try { await loadFiles(); - if (uploaded > 0) setNotice(t('authFiles.uploaded', { count: uploaded })); + if (uploaded > 0) showNotice(t('authFiles.uploaded', { count: uploaded })); if (failures.length > 0) setError(t('authFiles.uploadFailed', { count: failures.length, errors: failures.join('; ') })); } catch (requestError) { setError(String(requestError)); @@ -363,7 +377,7 @@ export function AuthFileManagementPage() { name, disabled: !readBoolean(file, 'disabled'), }); - setNotice(readBoolean(file, 'disabled') ? t('authFiles.notice.enabled') : t('authFiles.notice.disabled')); + showNotice(readBoolean(file, 'disabled') ? t('authFiles.notice.enabled') : t('authFiles.notice.disabled')); await loadFiles(); } catch (requestError) { setError(String(requestError)); @@ -406,7 +420,7 @@ export function AuthFileManagementPage() { try { await managementApi.patch('/auth-files/fields', { name, priority }); setPriorityEditor(null); - setNotice(t('authFiles.priority.updated', { name })); + showNotice(t('authFiles.priority.updated', { name })); await loadFiles(); } catch (requestError) { setPriorityEditor((current) => current @@ -428,7 +442,7 @@ export function AuthFileManagementPage() { setError(''); try { await managementApi.delete('/auth-files', { query: { name } }); - setNotice(t('authFiles.deleted')); + showNotice(t('authFiles.deleted')); await loadFiles(); } catch (requestError) { setError(String(requestError)); @@ -485,7 +499,12 @@ export function AuthFileManagementPage() { {error ?
{error}
: null} - {notice ?
{notice}
: null} + {notice ? ( +
+
+ ) : null}
diff --git a/src/pages/VersionManagementPage.tsx b/src/pages/VersionManagementPage.tsx index b616e79..f820001 100644 --- a/src/pages/VersionManagementPage.tsx +++ b/src/pages/VersionManagementPage.tsx @@ -153,6 +153,7 @@ export function VersionManagementPage() { const customMirrorInputRef = useRef(null); const latestCheckEpochRef = useRef(0); const toastTimerRef = useRef(null); + const completedInstallKeyRef = useRef(''); const showToast = (message: string, tone: MessageType = 'info') => { if (toastTimerRef.current !== null) { @@ -165,6 +166,13 @@ export function VersionManagementPage() { }, 4000); }; + const showInstallCompletedToast = (result: CoreInstallResult, message?: string | null) => { + const key = `${result.version}\u0000${result.assetName}\u0000${result.binaryPath ?? ''}`; + if (completedInstallKeyRef.current === key) return; + completedInstallKeyRef.current = key; + showToast(message || t('kernel.install.completed', { version: result.version }), 'success'); + }; + const applyInstallTask = (task: CoreInstallTask, showFinishedDialog = true) => { if (!task.running && !task.message && !task.result) { setProgress(null); @@ -186,7 +194,10 @@ export function VersionManagementPage() { } if (task.result) { - showToast(task.message || t('kernel.install.completed', { version: task.result.version }), 'success'); + showInstallCompletedToast(task.result, task.message); + setInstallDialogOpen(false); + setProgress(null); + setCancellingInstall(false); void refreshStatus(); return; } @@ -310,6 +321,7 @@ export function VersionManagementPage() { }; const installVersion = async (version: string) => { + completedInstallKeyRef.current = ''; setInstalling(true); setCancellingInstall(false); setInstallDialogOpen(true); @@ -326,7 +338,7 @@ export function VersionManagementPage() { try { const result = await invoke('install_core_version', { version }); - showToast(t('kernel.install.completed', { version: result.version }), 'success'); + showInstallCompletedToast(result, t('kernel.install.completed', { version: result.version })); setProgress({ running: false, cancellable: false, @@ -337,6 +349,9 @@ export function VersionManagementPage() { message: t('kernel.install.completed', { version: result.version }), result, }); + setInstallDialogOpen(false); + setProgress(null); + setCancellingInstall(false); await refreshStatus(); } catch (error) { const errorMessage = String(error);