From e56711b2dbda7d44a81d018be15a541f97d75181 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Wed, 28 Oct 2026 06:18:08 +0800 Subject: [PATCH] refactor(frontend): drop unused params, props and api surface Remove the never-read _revalidate argument of mutateVerge and its 16 call-site placeholders, seven never-passed props of the split chip editor, the unconsumed refreshDecorated context member, the now-orphaned toggleFullscreen control, the unused translate argument of the notice message handler, the reserved-but-unset ServiceConfig.timeout field and unreachable branches in parseNoticeExtras. --- .../base/base-split-chip-editor.tsx | 43 ++++++------------- src/components/home/test-card.tsx | 6 +-- src/components/layout/layout-sidebar.tsx | 5 +-- .../proxy/use-proxy-group-header-layout.ts | 6 +-- .../setting/mods/backup-config-viewer.tsx | 20 ++++----- src/components/setting/mods/layout-viewer.tsx | 2 +- .../setting/mods/sysproxy-viewer.tsx | 2 +- src/components/setting/mods/web-ui-viewer.tsx | 6 +-- src/components/setting/setting-system.tsx | 2 +- .../setting/setting-verge-basic.tsx | 2 +- .../shared/proxy-control-switches.tsx | 2 +- src/hooks/use-system-proxy-state.ts | 10 ++--- src/hooks/use-verge.ts | 1 - src/hooks/use-window.ts | 24 +++-------- src/pages/_layout.tsx | 6 +-- src/providers/window/window-context.ts | 2 - src/providers/window/window-provider.tsx | 8 ---- src/services/api.ts | 7 ++- src/services/bus/create-bus-handlers.test.ts | 6 +-- src/services/notice-handlers.ts | 2 - src/services/notice-service.ts | 9 ---- 21 files changed, 54 insertions(+), 117 deletions(-) diff --git a/src/components/base/base-split-chip-editor.tsx b/src/components/base/base-split-chip-editor.tsx index 75c21d020..3f6a86d7b 100644 --- a/src/components/base/base-split-chip-editor.tsx +++ b/src/components/base/base-split-chip-editor.tsx @@ -22,23 +22,16 @@ interface BaseSplitChipEditorProps { error?: boolean helperText?: ReactNode placeholder?: string - rows?: number separator?: string - splitPattern?: RegExp - defaultMode?: BaseSplitChipEditorMode - showModeToggle?: boolean ariaLabel?: string - addLabel?: ReactNode - emptyLabel?: ReactNode - modeLabels?: Partial> renderHeader?: (modeToggle: ReactNode) => ReactNode } const DEFAULT_SPLIT_PATTERN = /[,\n;\r]+/ -const splitValue = (value: string, splitPattern: RegExp) => +const splitValue = (value: string) => value - .split(splitPattern) + .split(DEFAULT_SPLIT_PATTERN) .map((item) => item.trim()) .filter(Boolean) @@ -49,35 +42,25 @@ export const BaseSplitChipEditor = ({ error = false, helperText, placeholder, - rows = 4, separator = ',', - splitPattern = DEFAULT_SPLIT_PATTERN, - defaultMode = 'visual', - showModeToggle = true, ariaLabel, - addLabel, - emptyLabel, - modeLabels, renderHeader, }: BaseSplitChipEditorProps) => { const { t } = useTranslation() - const [mode, setMode] = useState(defaultMode) + const [mode, setMode] = useState('visual') const [draft, setDraft] = useState('') const resolvedLabels = useMemo( () => ({ - visual: modeLabels?.visual ?? t('shared.editorModes.visualization'), - advanced: modeLabels?.advanced ?? t('shared.editorModes.advanced'), - add: addLabel ?? t('shared.actions.new'), - empty: emptyLabel ?? t('shared.statuses.empty'), + visual: t('shared.editorModes.visualization'), + advanced: t('shared.editorModes.advanced'), + add: t('shared.actions.new'), + empty: t('shared.statuses.empty'), }), - [t, modeLabels, addLabel, emptyLabel], + [t], ) - const values = useMemo( - () => splitValue(value, splitPattern), - [value, splitPattern], - ) + const values = useMemo(() => splitValue(value), [value]) const items = useMemo(() => { const counts = new Map() @@ -92,7 +75,7 @@ export const BaseSplitChipEditor = ({ }, [values]) const handleAddDraft = () => { - const nextValues = splitValue(draft, splitPattern) + const nextValues = splitValue(draft) if (!nextValues.length) { return } @@ -113,7 +96,7 @@ export const BaseSplitChipEditor = ({ const resolvedAriaLabel = ariaLabel ?? (typeof toggleLabel === 'string' ? toggleLabel : undefined) - const modeToggle = showModeToggle ? ( + const modeToggle = ( - ) : null + ) return ( <> @@ -202,7 +185,7 @@ export const BaseSplitChipEditor = ({ disabled={disabled} size="small" multiline - rows={rows} + rows={4} sx={{ width: '100%' }} value={value} helperText={helperText} diff --git a/src/components/home/test-card.tsx b/src/components/home/test-card.tsx index 5371f995e..77e854357 100644 --- a/src/components/home/test-card.tsx +++ b/src/components/home/test-card.tsx @@ -87,7 +87,7 @@ export const TestCard = () => { x.uid === uid ? { ...x, ...patch } : x, ) - mutateVerge({ ...verge, test_list: newList }, false) + mutateVerge({ ...verge, test_list: newList }) }, [testList, verge, mutateVerge], ) @@ -96,7 +96,7 @@ export const TestCard = () => { (uid: string) => { const newList = testList.filter((x) => x.uid !== uid) patchVerge({ test_list: newList }) - mutateVerge({ ...verge, test_list: newList }, false) + mutateVerge({ ...verge, test_list: newList }) }, [testList, verge, patchVerge, mutateVerge], ) @@ -129,7 +129,7 @@ export const TestCard = () => { newList.splice(newIndex, 0, removed) // 优化:先本地更新,再异步 patch,避免UI卡死 - mutateVerge({ ...verge, test_list: newList }, false) + mutateVerge({ ...verge, test_list: newList }) const patchFn = () => { try { patchVerge({ test_list: newList }) diff --git a/src/components/layout/layout-sidebar.tsx b/src/components/layout/layout-sidebar.tsx index f1a2be2f2..17a1df7d6 100644 --- a/src/components/layout/layout-sidebar.tsx +++ b/src/components/layout/layout-sidebar.tsx @@ -35,10 +35,7 @@ export const LayoutSidebar = (props: LayoutSidebarProps) => { const handleMenuOrderOptimisticUpdate = useCallback( (order: string[]) => { - mutateVerge( - (prev) => (prev ? { ...prev, menu_order: order } : prev), - false, - ) + mutateVerge((prev) => (prev ? { ...prev, menu_order: order } : prev)) }, [mutateVerge], ) diff --git a/src/components/proxy/use-proxy-group-header-layout.ts b/src/components/proxy/use-proxy-group-header-layout.ts index d3bb1b1c4..ab6bd700e 100644 --- a/src/components/proxy/use-proxy-group-header-layout.ts +++ b/src/components/proxy/use-proxy-group-header-layout.ts @@ -30,10 +30,8 @@ export const useProxyGroupHeaderLayout = () => { if (canceled || !operation.source || !operation.target) return const position = toolsOnLeft ? 'right' : 'left' - mutateVerge( - (prev) => - prev ? { ...prev, proxy_group_tools_position: position } : prev, - false, + mutateVerge((prev) => + prev ? { ...prev, proxy_group_tools_position: position } : prev, ) try { await patchVerge({ proxy_group_tools_position: position }) diff --git a/src/components/setting/mods/backup-config-viewer.tsx b/src/components/setting/mods/backup-config-viewer.tsx index c0ce70c10..9e6c028e5 100644 --- a/src/components/setting/mods/backup-config-viewer.tsx +++ b/src/components/setting/mods/backup-config-viewer.tsx @@ -113,17 +113,15 @@ export const BackupConfigViewer = memo( errorNotice: false, }, ) - await mutateVerge( - (current) => - current - ? { - ...current, - webdav_url: trimmedUrl, - webdav_username: trimmedUsername, - webdav_password: data.password, - } - : current, - false, + await mutateVerge((current) => + current + ? { + ...current, + webdav_url: trimmedUrl, + webdav_username: trimmedUsername, + webdav_password: data.password, + } + : current, ) setWebdavStatus(signature, 'unknown') showNotice.success('settings.modals.backup.messages.webdavConfigSaved') diff --git a/src/components/setting/mods/layout-viewer.tsx b/src/components/setting/mods/layout-viewer.tsx index f818d61de..504d4a382 100644 --- a/src/components/setting/mods/layout-viewer.tsx +++ b/src/components/setting/mods/layout-viewer.tsx @@ -107,7 +107,7 @@ export const LayoutViewer = forwardRef((_, ref) => { showNotice.error(err) } const onChangeData = (patch: Partial) => { - mutateVerge({ ...verge, ...patch }, false) + mutateVerge({ ...verge, ...patch }) } return ( diff --git a/src/components/setting/mods/sysproxy-viewer.tsx b/src/components/setting/mods/sysproxy-viewer.tsx index 09f5472c4..2e1d6ff31 100644 --- a/src/components/setting/mods/sysproxy-viewer.tsx +++ b/src/components/setting/mods/sysproxy-viewer.tsx @@ -339,7 +339,7 @@ export const SysproxyViewer = forwardRef((props, ref) => { Promise.resolve().then(async () => { try { if (Object.keys(patch).length > 0) { - mutateVerge({ ...verge, ...patch }, false) + mutateVerge({ ...verge, ...patch }) } if (Object.keys(patch).length > 0) { await patchVerge(patch) diff --git a/src/components/setting/mods/web-ui-viewer.tsx b/src/components/setting/mods/web-ui-viewer.tsx index 0cb24653f..7fdbfd5b2 100644 --- a/src/components/setting/mods/web-ui-viewer.tsx +++ b/src/components/setting/mods/web-ui-viewer.tsx @@ -50,21 +50,21 @@ export function WebUIViewer({ ref }: { ref?: Ref }) { const handleAdd = useLockFn(async (value: string) => { const newList = [...webUIList, value] - mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old), false) + mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old)) await patchVerge({ web_ui_list: newList }) }) const handleChange = useLockFn(async (index: number, value?: string) => { const newList = [...webUIList] newList[index] = value ?? '' - mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old), false) + mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old)) await patchVerge({ web_ui_list: newList }) }) const handleDelete = useLockFn(async (index: number) => { const newList = [...webUIList] newList.splice(index, 1) - mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old), false) + mutateVerge((old) => (old ? { ...old, web_ui_list: newList } : old)) await patchVerge({ web_ui_list: newList }) }) diff --git a/src/components/setting/setting-system.tsx b/src/components/setting/setting-system.tsx index c7ce131a1..edf02f5d6 100644 --- a/src/components/setting/setting-system.tsx +++ b/src/components/setting/setting-system.tsx @@ -29,7 +29,7 @@ const SettingSystem = ({ onError }: Props) => { value: boolean, ) => value const onChangeData = (patch: Partial) => { - mutateVerge({ ...verge, ...patch }, false) + mutateVerge({ ...verge, ...patch }) } return ( diff --git a/src/components/setting/setting-verge-basic.tsx b/src/components/setting/setting-verge-basic.tsx index 0dba7f952..ab3a394c1 100644 --- a/src/components/setting/setting-verge-basic.tsx +++ b/src/components/setting/setting-verge-basic.tsx @@ -72,7 +72,7 @@ const SettingVergeBasic = ({ onError }: Props) => { const backupRef = useRef(null) const onChangeData = (patch: any) => { - mutateVerge({ ...verge, ...patch }, false) + mutateVerge({ ...verge, ...patch }) } const onCopyClashEnv = useCallback(async () => { diff --git a/src/components/shared/proxy-control-switches.tsx b/src/components/shared/proxy-control-switches.tsx index 8f77df4dd..176d1f999 100644 --- a/src/components/shared/proxy-control-switches.tsx +++ b/src/components/shared/proxy-control-switches.tsx @@ -163,7 +163,7 @@ const ProxyControlSwitches = ({ }) return false } - mutateVerge({ ...verge, enable_tun_mode: value }, false) + mutateVerge({ ...verge, enable_tun_mode: value }) await patchVerge({ enable_tun_mode: value }) } diff --git a/src/hooks/use-system-proxy-state.ts b/src/hooks/use-system-proxy-state.ts index 974b0d63a..75ab9c6bc 100644 --- a/src/hooks/use-system-proxy-state.ts +++ b/src/hooks/use-system-proxy-state.ts @@ -52,9 +52,8 @@ export const useSystemProxyState = () => { const toggleSystemProxy = async (enabled: boolean) => { // Roll failed optimistic writes back to the latest confirmed state. let confirmed = verge?.enable_system_proxy ?? false - mutateVerge( - (prev) => (prev ? { ...prev, enable_system_proxy: enabled } : prev), - false, + mutateVerge((prev) => + prev ? { ...prev, enable_system_proxy: enabled } : prev, ) pendingRef.current = enabled @@ -78,9 +77,8 @@ export const useSystemProxyState = () => { } } } catch (error) { - mutateVerge( - (prev) => (prev ? { ...prev, enable_system_proxy: confirmed } : prev), - false, + mutateVerge((prev) => + prev ? { ...prev, enable_system_proxy: confirmed } : prev, ) // Queued requests were based on a state that never landed. pendingRef.current = null diff --git a/src/hooks/use-verge.ts b/src/hooks/use-verge.ts index 119b4ce1f..553c558b6 100644 --- a/src/hooks/use-verge.ts +++ b/src/hooks/use-verge.ts @@ -25,7 +25,6 @@ export const useVerge = () => { | IVergeConfig | ((prev: IVergeConfig | undefined) => IVergeConfig | undefined) | undefined, - _revalidate?: boolean, ) => { if (updaterOrData === undefined) { void refetch() diff --git a/src/hooks/use-window.ts b/src/hooks/use-window.ts index 15bee2c18..d3fa738a8 100644 --- a/src/hooks/use-window.ts +++ b/src/hooks/use-window.ts @@ -11,36 +11,24 @@ const useWindow = () => { } export const useWindowControls = () => { - const { - maximized, - minimize, - toggleMaximize, - close, - toggleFullscreen, - currentWindow, - } = useWindow() + const { maximized, minimize, toggleMaximize, close, currentWindow } = + useWindow() return { maximized, minimize, toggleMaximize, close, - toggleFullscreen, currentWindow, } satisfies Pick< WindowContextType, - | 'maximized' - | 'minimize' - | 'toggleMaximize' - | 'close' - | 'toggleFullscreen' - | 'currentWindow' + 'maximized' | 'minimize' | 'toggleMaximize' | 'close' | 'currentWindow' > } export const useWindowDecorations = () => { - const { decorated, toggleDecorations, refreshDecorated } = useWindow() - return { decorated, toggleDecorations, refreshDecorated } satisfies Pick< + const { decorated, toggleDecorations } = useWindow() + return { decorated, toggleDecorations } satisfies Pick< WindowContextType, - 'decorated' | 'toggleDecorations' | 'refreshDecorated' + 'decorated' | 'toggleDecorations' > } diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index b7c6ec930..8e49d1e81 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -2,7 +2,6 @@ import { Paper, ThemeProvider } from '@mui/material' import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import { useCallback, useEffect, useMemo } from 'react' -import { useTranslation } from 'react-i18next' import { Outlet, useNavigate } from 'react-router' import { BaseErrorBoundary } from '@/components/base' @@ -38,7 +37,6 @@ const OS = getSystem() const Layout = () => { const mode = useThemeMode() const isDark = mode !== 'light' - const { t } = useTranslation() const { theme } = useCustomTheme() const { verge } = useVerge() const { language } = verge ?? {} @@ -68,12 +66,12 @@ const Layout = () => { (payload: [string, string]) => { const [status, msg] = payload try { - handleNoticeMessage(status, msg, t, navigate) + handleNoticeMessage(status, msg, navigate) } catch (error) { console.error('[通知处理] 失败:', error) } }, - [t, navigate], + [navigate], ) useEventBus(handleNotice) diff --git a/src/providers/window/window-context.ts b/src/providers/window/window-context.ts index 2bd7a5905..fd995e8d4 100644 --- a/src/providers/window/window-context.ts +++ b/src/providers/window/window-context.ts @@ -5,11 +5,9 @@ export interface WindowContextType { decorated: boolean | null maximized: boolean | null toggleDecorations: () => Promise - refreshDecorated: () => Promise minimize: () => Promise close: () => Promise toggleMaximize: () => Promise - toggleFullscreen: () => Promise currentWindow: ReturnType } diff --git a/src/providers/window/window-provider.tsx b/src/providers/window/window-provider.tsx index 2c25325db..8a8893d2b 100644 --- a/src/providers/window/window-provider.tsx +++ b/src/providers/window/window-provider.tsx @@ -61,10 +61,6 @@ export const WindowProvider: React.FC<{ children: React.ReactNode }> = ({ } }, [currentWindow]) - const toggleFullscreen = useCallback(async () => { - await currentWindow.setFullscreen(!(await currentWindow.isFullscreen())) - }, [currentWindow]) - const refreshDecorated = useCallback(async () => { const val = await currentWindow.isDecorated() setDecorated(val) @@ -87,22 +83,18 @@ export const WindowProvider: React.FC<{ children: React.ReactNode }> = ({ decorated, maximized, toggleDecorations, - refreshDecorated, minimize, close, toggleMaximize, - toggleFullscreen, currentWindow, }), [ decorated, maximized, toggleDecorations, - refreshDecorated, minimize, close, toggleMaximize, - toggleFullscreen, currentWindow, ], ) diff --git a/src/services/api.ts b/src/services/api.ts index b7f6641a2..1e8e3018f 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -35,7 +35,6 @@ interface IpInfo { interface ServiceConfig { url: string mapping: (data: any) => IpInfo - timeout?: number // 保留timeout字段(如有需要) } // 可用的IP检测服务列表及字段映射 @@ -159,7 +158,7 @@ export const getIpInfo = async (): Promise< const timeoutController = new AbortController() const timeoutId = setTimeout(() => { timeoutController.abort() - }, service.timeout || serviceTimeout) + }, serviceTimeout) try { return await asyncRetry( @@ -168,8 +167,8 @@ export const getIpInfo = async (): Promise< const response = await fetch(service.url, { method: 'GET', - signal: timeoutController.signal, // AbortSignal.timeout(service.timeout || serviceTimeout), - connectTimeout: service.timeout || serviceTimeout, + signal: timeoutController.signal, // AbortSignal.timeout(serviceTimeout), + connectTimeout: serviceTimeout, headers: { 'User-Agent': userAgent, }, diff --git a/src/services/bus/create-bus-handlers.test.ts b/src/services/bus/create-bus-handlers.test.ts index 33bd6d602..844e40d33 100644 --- a/src/services/bus/create-bus-handlers.test.ts +++ b/src/services/bus/create-bus-handlers.test.ts @@ -51,7 +51,7 @@ const mountBus = async () => { return createEventBus({ dispatch, handleNotice: ([status, message]: [string, string]) => { - notice(status, message, (key) => key, vi.fn()) + notice(status, message, vi.fn()) }, revalidateKeys: (keys) => void revalidateQueries(keys.map((key) => [key])), readPendingFailures: () => {}, @@ -72,7 +72,7 @@ it('does not replay a recovered startup error after WebView recreation', async ( kind: 'startFailed', detail: 'startup failed', }) - first.handleNoticeMessage('core_start::error', '', (key) => key, vi.fn()) + first.handleNoticeMessage('core_start::error', '', vi.fn()) await flush() expect(showNotice.error).toHaveBeenCalledOnce() @@ -81,7 +81,7 @@ it('does not replay a recovered startup error after WebView recreation', async ( vi.mocked(getCoreStartupError).mockResolvedValue(null) vi.resetModules() const recreated = await import('@/services/notice-handlers') - recreated.handleNoticeMessage('core_start::error', '', (key) => key, vi.fn()) + recreated.handleNoticeMessage('core_start::error', '', vi.fn()) await flush() expect(showNotice.error).toHaveBeenCalledOnce() }) diff --git a/src/services/notice-handlers.ts b/src/services/notice-handlers.ts index 669853a4c..3a8ff5eba 100644 --- a/src/services/notice-handlers.ts +++ b/src/services/notice-handlers.ts @@ -13,7 +13,6 @@ import { hideNotice, showNotice } from '@/services/notice-service' import { requestService } from '@/services/service-request' type NavigateFunction = (path: string, options?: any) => void -type TranslateFunction = (key: string) => string let shownStartupError: string | null = null // Reads can settle out of order; only the newest may act, and a reset counts as one. @@ -241,7 +240,6 @@ const handlers: Record< export const handleNoticeMessage = ( status: string, msg: string, - t: TranslateFunction, navigate: NavigateFunction, ) => { const handler = handlers[status as NoticeStatus] diff --git a/src/services/notice-service.ts b/src/services/notice-service.ts index c36a0a85b..6e1784cad 100644 --- a/src/services/notice-service.ts +++ b/src/services/notice-service.ts @@ -148,15 +148,6 @@ function parseNoticeExtras(extras: NoticeExtra[]): ParsedNoticeExtras { raw = extra continue } - - if (!params && isPlainRecord(extra)) { - params = extra - continue - } - - if (duration === undefined && typeof extra === 'number') { - duration = extra - } } return {