From db376c75040b4488f947d9b90787f91cfd652ec9 Mon Sep 17 00:00:00 2001 From: LTbinglingfeng Date: Sat, 3 Jan 2026 01:40:54 +0800 Subject: [PATCH] fix(layout): wire header refresh to page loaders and quota config refresh --- src/components/layout/MainLayout.tsx | 21 +++++++++++++----- src/hooks/index.ts | 1 + src/hooks/useHeaderRefresh.ts | 24 +++++++++++++++++++++ src/pages/AuthFilesPage.tsx | 32 +++++++++++++++++++--------- src/pages/LogsPage.tsx | 3 +++ src/pages/QuotaPage.tsx | 27 ++++++++++++++++------- src/pages/UsagePage.tsx | 3 +++ 7 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 src/hooks/useHeaderRefresh.ts diff --git a/src/components/layout/MainLayout.tsx b/src/components/layout/MainLayout.tsx index 1a3b8bf..4226607 100644 --- a/src/components/layout/MainLayout.tsx +++ b/src/components/layout/MainLayout.tsx @@ -36,6 +36,7 @@ import { useThemeStore, } from '@/stores'; import { configApi, versionApi } from '@/services/api'; +import { triggerHeaderRefresh } from '@/hooks/useHeaderRefresh'; const sidebarIcons: Record = { dashboard: , @@ -384,12 +385,22 @@ export function MainLayout() { const handleRefreshAll = async () => { clearCache(); - try { - await fetchConfig(undefined, true); - showNotification(t('notification.data_refreshed'), 'success'); - } catch (error: any) { - showNotification(`${t('notification.refresh_failed')}: ${error?.message || ''}`, 'error'); + const results = await Promise.allSettled([ + fetchConfig(undefined, true), + triggerHeaderRefresh() + ]); + const rejected = results.find((result) => result.status === 'rejected'); + if (rejected && rejected.status === 'rejected') { + const reason = rejected.reason; + const message = + typeof reason === 'string' ? reason : reason instanceof Error ? reason.message : ''; + showNotification( + `${t('notification.refresh_failed')}${message ? `: ${message}` : ''}`, + 'error' + ); + return; } + showNotification(t('notification.data_refreshed'), 'success'); }; const handleVersionCheck = async () => { diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 6dc876f..ee756c7 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -8,3 +8,4 @@ export { useLocalStorage } from './useLocalStorage'; export { useInterval } from './useInterval'; export { useMediaQuery } from './useMediaQuery'; export { usePagination } from './usePagination'; +export { useHeaderRefresh } from './useHeaderRefresh'; diff --git a/src/hooks/useHeaderRefresh.ts b/src/hooks/useHeaderRefresh.ts new file mode 100644 index 0000000..88f60e4 --- /dev/null +++ b/src/hooks/useHeaderRefresh.ts @@ -0,0 +1,24 @@ +import { useEffect } from 'react'; + +export type HeaderRefreshHandler = () => void | Promise; + +let activeHeaderRefreshHandler: HeaderRefreshHandler | null = null; + +export const triggerHeaderRefresh = async () => { + if (!activeHeaderRefreshHandler) return; + await activeHeaderRefreshHandler(); +}; + +export const useHeaderRefresh = (handler?: HeaderRefreshHandler | null) => { + useEffect(() => { + if (!handler) return; + + activeHeaderRefreshHandler = handler; + + return () => { + if (activeHeaderRefreshHandler === handler) { + activeHeaderRefreshHandler = null; + } + }; + }, [handler]); +}; diff --git a/src/pages/AuthFilesPage.tsx b/src/pages/AuthFilesPage.tsx index fdabaa3..35aa4e9 100644 --- a/src/pages/AuthFilesPage.tsx +++ b/src/pages/AuthFilesPage.tsx @@ -1,8 +1,9 @@ -import { useEffect, useMemo, useRef, useState, useCallback } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useInterval } from '@/hooks/useInterval'; -import { Card } from '@/components/ui/Card'; -import { Button } from '@/components/ui/Button'; +import { useEffect, useMemo, useRef, useState, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useInterval } from '@/hooks/useInterval'; +import { useHeaderRefresh } from '@/hooks/useHeaderRefresh'; +import { Card } from '@/components/ui/Card'; +import { Button } from '@/components/ui/Button'; import { LoadingSpinner } from '@/components/ui/LoadingSpinner'; import { Input } from '@/components/ui/Input'; import { Modal } from '@/components/ui/Modal'; @@ -270,6 +271,12 @@ export function AuthFilesPage() { } }, [showNotification, t]); + const handleHeaderRefresh = useCallback(async () => { + await Promise.all([loadFiles(), loadKeyStats(), loadExcluded()]); + }, [loadFiles, loadKeyStats, loadExcluded]); + + useHeaderRefresh(handleHeaderRefresh); + useEffect(() => { loadFiles(); loadKeyStats(); @@ -824,11 +831,16 @@ export function AuthFilesPage() { - + extra={ +
+ -
{error &&
{error}
} diff --git a/src/pages/UsagePage.tsx b/src/pages/UsagePage.tsx index ba25420..14e61f0 100644 --- a/src/pages/UsagePage.tsx +++ b/src/pages/UsagePage.tsx @@ -14,6 +14,7 @@ import { import { Button } from '@/components/ui/Button'; import { LoadingSpinner } from '@/components/ui/LoadingSpinner'; import { useMediaQuery } from '@/hooks/useMediaQuery'; +import { useHeaderRefresh } from '@/hooks/useHeaderRefresh'; import { useThemeStore } from '@/stores'; import { StatCards, @@ -63,6 +64,8 @@ export function UsagePage() { importing } = useUsageData(); + useHeaderRefresh(loadUsage); + // Chart lines state const [chartLines, setChartLines] = useState(['all']); const MAX_CHART_LINES = 9;