mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-06-28 02:31:53 +08:00
fix: update error handling to avoid unused catch variables and improve code clarity
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -49,7 +49,7 @@ async function request<T = any>(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}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ export const AppWindowsLayer: React.FC<AppWindowsLayerProps> = ({ 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];
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useSystemStatus } from '../../contexts/SystemContext';
|
||||
|
||||
export const OfficeViewerApp: React.FC<AppComponentProps> = ({ filePath, onRequestClose }) => {
|
||||
const systemStatus = useSystemStatus();
|
||||
const fileDomain = systemStatus?.file_domain;
|
||||
const [url, setUrl] = useState<string>();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [err, setErr] = useState<string>();
|
||||
@@ -19,7 +20,7 @@ export const OfficeViewerApp: React.FC<AppComponentProps> = ({ 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<AppComponentProps> = ({ filePath, onReque
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [filePath]);
|
||||
}, [filePath, fileDomain]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
|
||||
@@ -47,7 +47,7 @@ export const PluginAppHost: React.FC<PluginAppHostProps> = ({ 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<PluginAppOpenHostProps> = ({ 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; }
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -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<AppComponentProps> = ({ 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;
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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<ThemeState>({ mode: 'light' });
|
||||
const stateRef = useRef(state);
|
||||
const styleTagRef = useRef<HTMLStyleElement | null>(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<ThemeState>) => {
|
||||
const next: ThemeState = { ...state, ...patch };
|
||||
const previewTheme = useCallback((patch: Partial<ThemeState>) => {
|
||||
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 (
|
||||
<Ctx.Provider value={ctxValue}>
|
||||
|
||||
@@ -30,6 +30,5 @@ export function useAsyncSafeEffect(
|
||||
ac.abort();
|
||||
}
|
||||
};
|
||||
}, deps);
|
||||
}, deps); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}
|
||||
|
||||
|
||||
@@ -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<string, string | number>)
|
||||
export function I18nProvider({ children }: PropsWithChildren) {
|
||||
const [lang, setLangState] = useState<Lang>(() => (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<string, string | number>) => {
|
||||
const t = useCallback((key: string, params?: Record<string, string | number>) => {
|
||||
const dict = dicts[lang] || {};
|
||||
const raw = dict[key] ?? key; // fallback to key (English)
|
||||
return interpolate(raw, params);
|
||||
};
|
||||
}, [lang]);
|
||||
|
||||
const value = useMemo<I18nContextValue>(() => ({ lang, setLang, t }), [lang]);
|
||||
const value = useMemo<I18nContextValue>(() => ({ lang, setLang, t }), [lang, setLang, t]);
|
||||
|
||||
return (
|
||||
<I18nContext.Provider value={value}>
|
||||
|
||||
@@ -302,7 +302,7 @@ const SearchDialog: React.FC<SearchDialogProps> = ({ open, onClose }) => {
|
||||
} else {
|
||||
setHasMore(false);
|
||||
}
|
||||
} catch (e) {
|
||||
} catch {
|
||||
if (requestId !== requestIdRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ const AdaptersPage = memo(function AdaptersPage() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
}, [t]);
|
||||
|
||||
useEffect(() => { fetchList(); }, [fetchList]);
|
||||
|
||||
|
||||
@@ -47,28 +47,24 @@ const AuditLogsPage = memo(function AuditLogsPage() {
|
||||
const [selectedLog, setSelectedLog] = useState<AuditLogItem | null>(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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -23,7 +23,7 @@ const SharePage = memo(function SharePage() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
}, [t]);
|
||||
|
||||
useEffect(() => { fetchList(); }, [fetchList]);
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user