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
This commit is contained in:
lzt404 committed 2026-09-01 23:32:26 +08:00
1 parent cbd82386d5
commit a34abfc587
3 files changed
+43 -9

No files matched your search

+1 -1
View File
@@ -1 +1 @@
7.2.145
7.2.146
+25 -6
View File
@@ -167,6 +167,16 @@ export function AuthFileManagementPage() {
const quotas = useQuotaCache();
const fileInputRef = useRef<HTMLInputElement | null>(null);
const oauthModelRequestRef = useRef(0);
const noticeTimerRef = useRef<number | null>(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() {
</header>
{error ? <div className="management-alert error">{error}</div> : null}
{notice ? <div className="management-alert success">{notice}</div> : null}
{notice ? (
<div className="config-toast success" role="status" title={notice}>
<Check size={17} aria-hidden="true" />
<span>{notice}</span>
</div>
) : null}
<section className="panel auth-files-panel real-auth-files-panel">
<div className="management-toolbar auth-files-toolbar">
+17 -2
View File
@@ -153,6 +153,7 @@ export function VersionManagementPage() {
const customMirrorInputRef = useRef<HTMLInputElement>(null);
const latestCheckEpochRef = useRef(0);
const toastTimerRef = useRef<number | null>(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<CoreInstallResult>('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);