From 7c38c0045bd24878e8767a19249aa2059549c3e3 Mon Sep 17 00:00:00 2001 From: shiyu Date: Thu, 18 Dec 2025 15:51:20 +0800 Subject: [PATCH] fix: update error handling to avoid unused catch variables and improve code clarity --- web/eslint.config.js | 10 ++++ web/src/api/client.ts | 2 +- web/src/api/vfs.ts | 4 +- web/src/apps/AppWindowsLayer.tsx | 4 +- web/src/apps/OfficeViewer/OfficeViewer.tsx | 5 +- web/src/apps/PluginHost/index.tsx | 4 +- web/src/apps/TextEditor/TextEditor.tsx | 3 +- web/src/apps/registry.ts | 5 +- web/src/contexts/AuthContext.tsx | 3 +- web/src/contexts/ThemeContext.tsx | 55 ++++++++++++------- web/src/hooks/useAsyncSafeEffect.ts | 3 +- web/src/i18n/index.tsx | 12 ++-- web/src/layout/SearchDialog.tsx | 2 +- web/src/pages/AdaptersPage.tsx | 2 +- web/src/pages/AuditLogsPage.tsx | 22 +++----- .../components/Modals/DirectLinkModal.tsx | 20 +++---- .../components/Modals/MoveCopyModal.tsx | 4 +- .../FileExplorerPage/hooks/useAppWindows.tsx | 4 +- .../FileExplorerPage/hooks/useFileActions.tsx | 10 ++-- .../FileExplorerPage/hooks/useProcessor.ts | 2 +- web/src/pages/PluginsPage.tsx | 18 +++--- .../pages/PublicSharePage/DirectoryViewer.tsx | 26 ++++----- web/src/pages/PublicSharePage/index.tsx | 16 +++--- web/src/pages/SharePage.tsx | 2 +- .../components/EmailSettingsTab.tsx | 2 +- web/src/plugins/runtime.ts | 3 +- 26 files changed, 130 insertions(+), 113 deletions(-) diff --git a/web/eslint.config.js b/web/eslint.config.js index d94e7de..e25fb50 100644 --- a/web/eslint.config.js +++ b/web/eslint.config.js @@ -15,6 +15,16 @@ export default tseslint.config([ reactHooks.configs['recommended-latest'], reactRefresh.configs.vite, ], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + 'react-refresh/only-export-components': [ + 'error', + { + allowConstantExport: true, + allowExportNames: ['routes', 'useAuth', 'useTheme', 'useAppWindows', 'useI18n'], + }, + ], + }, languageOptions: { ecmaVersion: 2020, globals: globals.browser, diff --git a/web/src/api/client.ts b/web/src/api/client.ts index 157dcb4..2351c0e 100644 --- a/web/src/api/client.ts +++ b/web/src/api/client.ts @@ -49,7 +49,7 @@ async function request(url: string, options: RequestOptions = {}): Prom } else { errMsg = (typeof data?.detail === 'string') ? data.detail : (data.detail ? JSON.stringify(data.detail) : JSON.stringify(data)); } - } catch (_) { } + } catch { void 0; } throw new Error(errMsg || `Request failed: ${resp.status}`); } diff --git a/web/src/api/vfs.ts b/web/src/api/vfs.ts index 6c39eab..7235cf4 100644 --- a/web/src/api/vfs.ts +++ b/web/src/api/vfs.ts @@ -107,7 +107,7 @@ export const vfsApi = { const json = JSON.parse(xhr.responseText); if (json.code === 0) return resolve(json.data); return reject(new Error(json.msg || json.message || 'Upload failed')); - } catch (e) { + } catch { return reject(new Error('Invalid response')); } } else { @@ -115,7 +115,7 @@ export const vfsApi = { try { const json = JSON.parse(xhr.responseText); err = json.detail || json.msg || json.message || err; - } catch (_) {} + } catch { void 0; } reject(new Error(err)); } } diff --git a/web/src/apps/AppWindowsLayer.tsx b/web/src/apps/AppWindowsLayer.tsx index f8c67e7..836ca5b 100644 --- a/web/src/apps/AppWindowsLayer.tsx +++ b/web/src/apps/AppWindowsLayer.tsx @@ -57,8 +57,8 @@ export const AppWindowsLayer: React.FC = ({ windows, onClo const { id, startX, startY, originX, originY } = dragRef.current; const dx = e.clientX - startX; const dy = e.clientY - startY; - let newX = Math.max(0, originX + dx); - let newY = Math.max(0, originY + dy); + const newX = Math.max(0, originX + dx); + const newY = Math.max(0, originY + dy); dragRef.current.newX = newX; dragRef.current.newY = newY; const el = windowEls.current[id]; diff --git a/web/src/apps/OfficeViewer/OfficeViewer.tsx b/web/src/apps/OfficeViewer/OfficeViewer.tsx index 6d44288..79bc7bc 100644 --- a/web/src/apps/OfficeViewer/OfficeViewer.tsx +++ b/web/src/apps/OfficeViewer/OfficeViewer.tsx @@ -6,6 +6,7 @@ import { useSystemStatus } from '../../contexts/SystemContext'; export const OfficeViewerApp: React.FC = ({ filePath, onRequestClose }) => { const systemStatus = useSystemStatus(); + const fileDomain = systemStatus?.file_domain; const [url, setUrl] = useState(); const [loading, setLoading] = useState(true); const [err, setErr] = useState(); @@ -19,7 +20,7 @@ export const OfficeViewerApp: React.FC = ({ filePath, onReque vfsApi.getTempLinkToken(filePath.replace(/^\/+/, '')) .then(res => { if (cancelled) return; - const baseUrl = systemStatus?.file_domain || window.location.origin; + const baseUrl = fileDomain || window.location.origin; const fullUrl = new URL(res.url, baseUrl).href; const officeUrl = `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(fullUrl)}`; setUrl(officeUrl); @@ -38,7 +39,7 @@ export const OfficeViewerApp: React.FC = ({ filePath, onReque return () => { cancelled = true; }; - }, [filePath]); + }, [filePath, fileDomain]); if (loading) { return ( diff --git a/web/src/apps/PluginHost/index.tsx b/web/src/apps/PluginHost/index.tsx index 6d8a104..fe7753a 100644 --- a/web/src/apps/PluginHost/index.tsx +++ b/web/src/apps/PluginHost/index.tsx @@ -47,7 +47,7 @@ export const PluginAppHost: React.FC = ({ plugin, filePath, if (pluginRef.current?.unmount && containerRef.current) { pluginRef.current.unmount(containerRef.current); } - } catch {} + } catch { void 0; } }, ); @@ -96,7 +96,7 @@ export const PluginAppOpenHost: React.FC = ({ plugin, on const p = pluginRef.current; if (p?.unmountApp) return p.unmountApp(containerRef.current); if (p?.unmount) return p.unmount(containerRef.current); - } catch { } + } catch { void 0; } }, ); diff --git a/web/src/apps/TextEditor/TextEditor.tsx b/web/src/apps/TextEditor/TextEditor.tsx index cc6c922..e846205 100644 --- a/web/src/apps/TextEditor/TextEditor.tsx +++ b/web/src/apps/TextEditor/TextEditor.tsx @@ -9,13 +9,14 @@ const MarkdownEditor = React.lazy(() => import('@uiw/react-md-editor')); const { Header, Content } = Layout; +const MAX_PREVIEW_BYTES = 1024 * 1024; // 1MB + export const TextEditorApp: React.FC = ({ filePath, entry, onRequestClose }) => { const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [content, setContent] = useState(''); const [initialContent, setInitialContent] = useState(''); const [truncated, setTruncated] = useState(false); - const MAX_PREVIEW_BYTES = 1024 * 1024; // 1MB const isDirty = content !== initialContent; const onRequestCloseRef = useRef(onRequestClose); onRequestCloseRef.current = onRequestClose; diff --git a/web/src/apps/registry.ts b/web/src/apps/registry.ts index 657b7a3..f17417f 100644 --- a/web/src/apps/registry.ts +++ b/web/src/apps/registry.ts @@ -21,8 +21,7 @@ async function loadApps() { try { const items = await pluginsApi.list(); items.filter(p => p.enabled !== false).forEach((p) => registerPluginAsApp(p)); - } catch (e) { - } + } catch { void 0; } } function registerPluginAsApp(p: PluginItem) { @@ -104,5 +103,5 @@ export async function reloadPluginApps() { : undefined; } }); - } catch { } + } catch { void 0; } } diff --git a/web/src/contexts/AuthContext.tsx b/web/src/contexts/AuthContext.tsx index ef730ab..0ec8ff6 100644 --- a/web/src/contexts/AuthContext.tsx +++ b/web/src/contexts/AuthContext.tsx @@ -27,7 +27,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { const res = await authApi.login({ username, password }); if (res) { setToken(res.access_token); - try { await refreshUser(); } catch (_) {} + try { await refreshUser(); } catch { void 0; } } }; @@ -52,7 +52,6 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { } else { setUser(null); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [token]); return ( diff --git a/web/src/contexts/ThemeContext.tsx b/web/src/contexts/ThemeContext.tsx index 7544471..a9eedc9 100644 --- a/web/src/contexts/ThemeContext.tsx +++ b/web/src/contexts/ThemeContext.tsx @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { ConfigProvider, theme as antdTheme } from 'antd'; import zhCN from 'antd/locale/zh_CN'; import enUS from 'antd/locale/en_US'; @@ -85,15 +85,22 @@ function buildThemeConfig(state: ThemeState, systemDark: boolean): ThemeConfig { const baseComponents = { ...(baseTheme.components as any) }; if (resolvedMode === 'dark' && baseComponents) { if (baseComponents.Menu) { - const { itemHoverColor, itemHoverBg, itemSelectedBg, itemSelectedColor, ...rest } = baseComponents.Menu; + const rest = { ...baseComponents.Menu }; + delete rest.itemHoverColor; + delete rest.itemHoverBg; + delete rest.itemSelectedBg; + delete rest.itemSelectedColor; baseComponents.Menu = rest; } if (baseComponents.Dropdown) { - const { controlItemBgHover, ...rest } = baseComponents.Dropdown; + const rest = { ...baseComponents.Dropdown }; + delete rest.controlItemBgHover; baseComponents.Dropdown = rest; } if (baseComponents.Table) { - const { headerBg, rowHoverBg, ...rest } = baseComponents.Table; + const rest = { ...baseComponents.Table }; + delete rest.headerBg; + delete rest.rowHoverBg; baseComponents.Table = rest; } } @@ -106,9 +113,14 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) { const { lang } = useI18n(); const systemDark = useSystemDarkPreferred(); const [state, setState] = useState({ mode: 'light' }); + const stateRef = useRef(state); const styleTagRef = useRef(null); - const ensureStyleTag = () => { + useEffect(() => { + stateRef.current = state; + }, [state]); + + const ensureStyleTag = useCallback(() => { if (styleTagRef.current) return styleTagRef.current; let styleEl = document.getElementById('foxel-custom-css') as HTMLStyleElement | null; if (!styleEl) { @@ -118,22 +130,22 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) { } styleTagRef.current = styleEl; return styleEl; - }; + }, []); - const applyCustomCSS = (cssText: string | null | undefined) => { + const applyCustomCSS = useCallback((cssText: string | null | undefined) => { const el = ensureStyleTag(); el.textContent = cssText || ''; - }; + }, [ensureStyleTag]); - const applyHtmlDataTheme = (mode: ThemeMode) => { + const applyHtmlDataTheme = useCallback((mode: ThemeMode) => { const finalMode = mode === 'system' ? (systemDark ? 'dark' : 'light') : mode; document.documentElement.setAttribute('data-theme', finalMode); - }; + }, [systemDark]); - const refreshTheme = async () => { + const refreshTheme = useCallback(async () => { if (!isAuthenticated) { - applyHtmlDataTheme(state.mode || 'light'); - applyCustomCSS(state.customCSS || ''); + applyHtmlDataTheme(stateRef.current.mode || 'light'); + applyCustomCSS(stateRef.current.customCSS || ''); return; } try { @@ -147,22 +159,23 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) { setState({ mode, primaryColor: primary, borderRadius: radius, customTokens, customCSS }); applyHtmlDataTheme(mode); applyCustomCSS(customCSS); - } catch (e) { + } catch { applyHtmlDataTheme('light'); applyCustomCSS(''); } - }; + }, [applyCustomCSS, applyHtmlDataTheme, isAuthenticated]); - const previewTheme = (patch: Partial) => { - const next: ThemeState = { ...state, ...patch }; + const previewTheme = useCallback((patch: Partial) => { + const next: ThemeState = { ...stateRef.current, ...patch }; + stateRef.current = next; setState(next); applyHtmlDataTheme(next.mode || 'light'); applyCustomCSS(next.customCSS || ''); - }; + }, [applyCustomCSS, applyHtmlDataTheme]); useEffect(() => { - refreshTheme(); - }, [isAuthenticated, systemDark]); + void refreshTheme(); + }, [refreshTheme]); const themeConfig = useMemo(() => buildThemeConfig(state, systemDark), [state, systemDark]); const resolvedMode: ThemeMode = useMemo(() => (state.mode === 'system' ? (systemDark ? 'dark' : 'light') : state.mode), [state.mode, systemDark]); @@ -173,7 +186,7 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) { previewTheme, mode: state.mode, resolvedMode, - }), [state.mode, resolvedMode]); + }), [previewTheme, refreshTheme, resolvedMode, state.mode]); return ( diff --git a/web/src/hooks/useAsyncSafeEffect.ts b/web/src/hooks/useAsyncSafeEffect.ts index d368835..90784f5 100644 --- a/web/src/hooks/useAsyncSafeEffect.ts +++ b/web/src/hooks/useAsyncSafeEffect.ts @@ -30,6 +30,5 @@ export function useAsyncSafeEffect( ac.abort(); } }; - }, deps); + }, deps); // eslint-disable-line react-hooks/exhaustive-deps } - diff --git a/web/src/i18n/index.tsx b/web/src/i18n/index.tsx index 1de429c..7b4d30c 100644 --- a/web/src/i18n/index.tsx +++ b/web/src/i18n/index.tsx @@ -1,4 +1,4 @@ -import { createContext, useContext, useMemo, useState, useEffect } from 'react'; +import { createContext, useCallback, useContext, useMemo, useState, useEffect } from 'react'; import type { PropsWithChildren } from 'react'; import en from './locales/en.json'; import zhOverrides from './locales/zh.json'; @@ -27,22 +27,22 @@ function interpolate(template: string, params?: Record) export function I18nProvider({ children }: PropsWithChildren) { const [lang, setLangState] = useState(() => (localStorage.getItem('lang') as Lang) || 'zh'); - const setLang = (l: Lang) => { + const setLang = useCallback((l: Lang) => { setLangState(l); localStorage.setItem('lang', l); - }; + }, []); useEffect(() => { document.documentElement.lang = lang; }, [lang]); - const t = (key: string, params?: Record) => { + const t = useCallback((key: string, params?: Record) => { const dict = dicts[lang] || {}; const raw = dict[key] ?? key; // fallback to key (English) return interpolate(raw, params); - }; + }, [lang]); - const value = useMemo(() => ({ lang, setLang, t }), [lang]); + const value = useMemo(() => ({ lang, setLang, t }), [lang, setLang, t]); return ( diff --git a/web/src/layout/SearchDialog.tsx b/web/src/layout/SearchDialog.tsx index bcf9222..0e0dd9c 100644 --- a/web/src/layout/SearchDialog.tsx +++ b/web/src/layout/SearchDialog.tsx @@ -302,7 +302,7 @@ const SearchDialog: React.FC = ({ open, onClose }) => { } else { setHasMore(false); } - } catch (e) { + } catch { if (requestId !== requestIdRef.current) { return; } diff --git a/web/src/pages/AdaptersPage.tsx b/web/src/pages/AdaptersPage.tsx index fe8031f..82a430a 100644 --- a/web/src/pages/AdaptersPage.tsx +++ b/web/src/pages/AdaptersPage.tsx @@ -27,7 +27,7 @@ const AdaptersPage = memo(function AdaptersPage() { } finally { setLoading(false); } - }, []); + }, [t]); useEffect(() => { fetchList(); }, [fetchList]); diff --git a/web/src/pages/AuditLogsPage.tsx b/web/src/pages/AuditLogsPage.tsx index da9b9c8..1054a17 100644 --- a/web/src/pages/AuditLogsPage.tsx +++ b/web/src/pages/AuditLogsPage.tsx @@ -47,28 +47,24 @@ const AuditLogsPage = memo(function AuditLogsPage() { const [selectedLog, setSelectedLog] = useState(null); const { t } = useI18n(); - const buildParams = () => { - const params: any = { ...filters }; - if (!params.action) delete params.action; - if (params.success === '') delete params.success; - if (!params.username) delete params.username; - if (!params.path) delete params.path; - if (!params.start_time) delete params.start_time; - if (!params.end_time) delete params.end_time; - return params; - }; - const fetchList = useCallback(async () => { setLoading(true); try { - const res = await auditApi.list(buildParams()); + const params: any = { ...filters }; + if (!params.action) delete params.action; + if (params.success === '') delete params.success; + if (!params.username) delete params.username; + if (!params.path) delete params.path; + if (!params.start_time) delete params.start_time; + if (!params.end_time) delete params.end_time; + const res = await auditApi.list(params); setData(res); } catch (e: any) { message.error(e.message || t('Load failed')); } finally { setLoading(false); } - }, [filters]); + }, [filters, t]); useEffect(() => { fetchList(); diff --git a/web/src/pages/FileExplorerPage/components/Modals/DirectLinkModal.tsx b/web/src/pages/FileExplorerPage/components/Modals/DirectLinkModal.tsx index 8b18804..a090cf0 100644 --- a/web/src/pages/FileExplorerPage/components/Modals/DirectLinkModal.tsx +++ b/web/src/pages/FileExplorerPage/components/Modals/DirectLinkModal.tsx @@ -1,4 +1,4 @@ -import { memo, useState, useEffect } from 'react'; +import { memo, useState, useEffect, useCallback } from 'react'; import { Modal, Radio, message, Button, Typography, Input, Space } from 'antd'; import { CopyOutlined, FileMarkdownOutlined } from '@ant-design/icons'; import type { VfsEntry } from '../../../../api/client'; @@ -33,14 +33,7 @@ export const DirectLinkModal = memo(function DirectLinkModal({ entry, path, open const [link, setLink] = useState(''); const { t } = useI18n(); - useEffect(() => { - if (open && entry) { - setLink(''); - generateLink(); - } - }, [open, entry, expiresIn]); - - const generateLink = async () => { + const generateLink = useCallback(async () => { if (!entry) return; setLoading(true); try { @@ -57,7 +50,14 @@ export const DirectLinkModal = memo(function DirectLinkModal({ entry, path, open } finally { setLoading(false); } - }; + }, [entry, expiresIn, path, t]); + + useEffect(() => { + if (open && entry) { + setLink(''); + void generateLink(); + } + }, [open, entry, generateLink]); const handleCopy = (text: string) => { navigator.clipboard.writeText(text); diff --git a/web/src/pages/FileExplorerPage/components/Modals/MoveCopyModal.tsx b/web/src/pages/FileExplorerPage/components/Modals/MoveCopyModal.tsx index 0ac45f2..e7e6145 100644 --- a/web/src/pages/FileExplorerPage/components/Modals/MoveCopyModal.tsx +++ b/web/src/pages/FileExplorerPage/components/Modals/MoveCopyModal.tsx @@ -41,9 +41,7 @@ export function MoveCopyModal({ mode, entries, open, defaultPath, onOk, onCancel try { await onOk(trimmed); onCancel(); - } catch (e) { - // 上层已处理提示,这里只需保持对话框 - } finally { + } catch { void 0; } finally { setLoading(false); } }; diff --git a/web/src/pages/FileExplorerPage/hooks/useAppWindows.tsx b/web/src/pages/FileExplorerPage/hooks/useAppWindows.tsx index 74d716d..d675cdc 100644 --- a/web/src/pages/FileExplorerPage/hooks/useAppWindows.tsx +++ b/web/src/pages/FileExplorerPage/hooks/useAppWindows.tsx @@ -47,7 +47,7 @@ export function useAppWindows(path: string) { } const defaultApp = getDefaultAppForEntry(entry) || apps[0]; openWithApp(entry, defaultApp); - }, [openWithApp]); + }, [openWithApp, t]); const confirmOpenWithApp = useCallback((entry: VfsEntry, appKey: string) => { const app = getAppByKey(appKey); @@ -72,7 +72,7 @@ export function useAppWindows(path: string) { openWithApp(entry, app); } }); - }, [openWithApp]); + }, [openWithApp, t]); const closeWindow = (id: string) => setAppWindows(ws => ws.filter(w => w.id !== id)); const toggleMax = (id: string) => setAppWindows(ws => ws.map(w => w.id === id ? { ...w, maximized: !w.maximized } : w)); diff --git a/web/src/pages/FileExplorerPage/hooks/useFileActions.tsx b/web/src/pages/FileExplorerPage/hooks/useFileActions.tsx index 9611d50..93040d8 100644 --- a/web/src/pages/FileExplorerPage/hooks/useFileActions.tsx +++ b/web/src/pages/FileExplorerPage/hooks/useFileActions.tsx @@ -35,7 +35,7 @@ export function useFileActions({ path, refresh, clearSelection, onShare, onGetDi } catch (e: any) { message.error(e.message); } - }, [path, refresh]); + }, [path, refresh, t]); const doDelete = useCallback(async (entries: VfsEntry[]) => { Modal.confirm({ @@ -51,7 +51,7 @@ export function useFileActions({ path, refresh, clearSelection, onShare, onGetDi } } }); - }, [path, refresh, clearSelection]); + }, [path, refresh, clearSelection, t]); const doRename = useCallback(async (entry: VfsEntry, newName: string) => { if (!newName.trim() || newName.trim() === entry.name) { @@ -173,7 +173,7 @@ export function useFileActions({ path, refresh, clearSelection, onShare, onGetDi } catch (e: any) { message.error(e.message || t('Download failed')); } - }, [path]); + }, [path, t]); const doShare = useCallback((entries: VfsEntry[]) => { if (entries.length === 0) { @@ -181,7 +181,7 @@ export function useFileActions({ path, refresh, clearSelection, onShare, onGetDi return; } onShare(entries); - }, [onShare]); + }, [onShare, t]); const doGetDirectLink = useCallback((entry: VfsEntry) => { if (entry.is_dir) { @@ -189,7 +189,7 @@ export function useFileActions({ path, refresh, clearSelection, onShare, onGetDi return; } onGetDirectLink(entry); - }, [onGetDirectLink]); + }, [onGetDirectLink, t]); return { doCreateDir, diff --git a/web/src/pages/FileExplorerPage/hooks/useProcessor.ts b/web/src/pages/FileExplorerPage/hooks/useProcessor.ts index 2d1cca9..8da8aa3 100644 --- a/web/src/pages/FileExplorerPage/hooks/useProcessor.ts +++ b/web/src/pages/FileExplorerPage/hooks/useProcessor.ts @@ -58,7 +58,7 @@ export function useProcessor({ path, processorTypes, refresh }: ProcessorParams) } finally { setLoading(false); } - }, [modal.entry, selectedProcessor, processorTypes, config, path, overwrite, savingPath, refresh]); + }, [modal.entry, selectedProcessor, processorTypes, config, path, overwrite, savingPath, refresh, t]); const handleCancel = useCallback(() => { setModal({ entry: null, visible: false }); diff --git a/web/src/pages/PluginsPage.tsx b/web/src/pages/PluginsPage.tsx index 33fdec1..e50e0aa 100644 --- a/web/src/pages/PluginsPage.tsx +++ b/web/src/pages/PluginsPage.tsx @@ -1,4 +1,4 @@ -import { memo, useEffect, useMemo, useState } from 'react'; +import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { Button, Modal, Form, Input, Tag, message, Card, Typography, Popconfirm, Empty, Skeleton, theme, Divider, Tabs, Select, Pagination } from 'antd'; import { GithubOutlined, LinkOutlined } from '@ant-design/icons'; import { pluginsApi, type PluginItem } from '../api/plugins'; @@ -38,7 +38,7 @@ const PluginsPage = memo(function PluginsPage() { try { await ensureAppsLoaded(); setSystemApps(listSystemApps()); - } catch {} + } catch { void 0; } })(); }, []); @@ -48,23 +48,23 @@ const PluginsPage = memo(function PluginsPage() { return set; }, [data]); - const reloadRepo = async () => { + const reloadRepo = useCallback(async () => { try { setRepoLoading(true); const res = await fetchRepoList({ query: repoQ || undefined, sort: repoSort, page: repoPage, pageSize: repoPageSize }); setRepoItems(res.items || []); setRepoTotal(res.total || 0); - } catch (e) { + } catch { setRepoItems([]); setRepoTotal(0); } finally { setRepoLoading(false); } - }; + }, [repoPage, repoPageSize, repoQ, repoSort]); useEffect(() => { if (tab === 'discover') reloadRepo(); - }, [tab, repoQ, repoSort, repoPage, repoPageSize]); + }, [reloadRepo, tab]); const handleAdd = async () => { try { @@ -73,13 +73,13 @@ const PluginsPage = memo(function PluginsPage() { try { const p = await loadPlugin(created); await ensureManifest(created.id, p); - } catch {} + } catch { void 0; } setAdding(false); form.resetFields(); await reload(); await reloadPluginApps(); message.success(t('Installed successfully')); - } catch {} + } catch { void 0; } }; const filtered = useMemo(() => { @@ -290,7 +290,7 @@ const PluginsPage = memo(function PluginsPage() { try { const p = await loadPlugin(created); await ensureManifest(created.id, p); - } catch {} + } catch { void 0; } await reload(); await reloadPluginApps(); message.success(t('Installed successfully')); diff --git a/web/src/pages/PublicSharePage/DirectoryViewer.tsx b/web/src/pages/PublicSharePage/DirectoryViewer.tsx index 5137a4e..2fd77b7 100644 --- a/web/src/pages/PublicSharePage/DirectoryViewer.tsx +++ b/web/src/pages/PublicSharePage/DirectoryViewer.tsx @@ -22,19 +22,19 @@ export const DirectoryViewer = memo(function DirectoryViewer({ token, shareInfo, const [error, setError] = useState(''); const { t } = useI18n(); - const loadData = useCallback(async (p: string) => { - setLoading(true); - setError(''); - try { - const listing = await shareApi.listDir(token, p, password); - setEntries(listing.entries || []); - setCurrentPath(p); - } catch (e: any) { - setError(e.message || t('Share load failed')); - } finally { - setLoading(false); - } - }, [token, password]); + const loadData = useCallback(async (p: string) => { + setLoading(true); + setError(''); + try { + const listing = await shareApi.listDir(token, p, password); + setEntries(listing.entries || []); + setCurrentPath(p); + } catch (e: any) { + setError(e.message || t('Share load failed')); + } finally { + setLoading(false); + } + }, [password, t, token]); useEffect(() => { loadData(currentPath); diff --git a/web/src/pages/PublicSharePage/index.tsx b/web/src/pages/PublicSharePage/index.tsx index 98efe05..9f22e90 100644 --- a/web/src/pages/PublicSharePage/index.tsx +++ b/web/src/pages/PublicSharePage/index.tsx @@ -17,10 +17,10 @@ const PublicSharePage = memo(function PublicSharePage() { const [verified, setVerified] = useState(false); const { t } = useI18n(); - const loadData = useCallback(async (pwd?: string) => { - if (!token) return; - setLoading(true); - setError(''); + const loadData = useCallback(async (pwd?: string) => { + if (!token) return; + setLoading(true); + setError(''); try { let info = shareInfo; if (!info) { @@ -50,10 +50,10 @@ const PublicSharePage = memo(function PublicSharePage() { if (e.message === '需要密码') { setVerified(false); } - } finally { - setLoading(false); - } - }, [token, shareInfo, password, verified]); + } finally { + setLoading(false); + } + }, [password, shareInfo, t, token, verified]); useEffect(() => { loadData(); diff --git a/web/src/pages/SharePage.tsx b/web/src/pages/SharePage.tsx index 23870c2..b8843ad 100644 --- a/web/src/pages/SharePage.tsx +++ b/web/src/pages/SharePage.tsx @@ -23,7 +23,7 @@ const SharePage = memo(function SharePage() { } finally { setLoading(false); } - }, []); + }, [t]); useEffect(() => { fetchList(); }, [fetchList]); diff --git a/web/src/pages/SystemSettingsPage/components/EmailSettingsTab.tsx b/web/src/pages/SystemSettingsPage/components/EmailSettingsTab.tsx index ff2b6b9..8646bd6 100644 --- a/web/src/pages/SystemSettingsPage/components/EmailSettingsTab.tsx +++ b/web/src/pages/SystemSettingsPage/components/EmailSettingsTab.tsx @@ -78,7 +78,7 @@ function parseEmailConfig(raw?: string | null): EmailFormValues { timeout: data?.timeout !== undefined ? Number(data.timeout) : DEFAULT_FORM.timeout, security: (data?.security ?? DEFAULT_FORM.security) as EmailFormValues['security'], }; - } catch (_err) { + } catch { return { ...DEFAULT_FORM }; } } diff --git a/web/src/plugins/runtime.ts b/web/src/plugins/runtime.ts index 4cf9e48..2382942 100644 --- a/web/src/plugins/runtime.ts +++ b/web/src/plugins/runtime.ts @@ -133,12 +133,13 @@ export async function ensureManifest(pluginId: number, plugin: RegisteredPlugin) website: plugin.website, github: plugin.github, }; - try { console.debug('[foxel] report manifest', pluginId, manifest); } catch { } + try { console.debug('[foxel] report manifest', pluginId, manifest); } catch { void 0; } const key = `foxel:manifestReported:${pluginId}`; if (sessionStorage.getItem(key) === '1') return; try { await pluginsApi.updateManifest(pluginId, manifest); sessionStorage.setItem(key, '1'); } catch { + void 0; } }