mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-11 03:59:09 +00:00
fix(settings): harden settings and diagnostic controls
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { invokeCommand as invoke } from '../ipc';
|
||||
import { save } from '@tauri-apps/plugin-dialog';
|
||||
import { homeDir } from '@tauri-apps/api/path';
|
||||
import { attachLogger, setLogPaused, initLogger, setLogStreamActive } from '../utils/logger';
|
||||
import { FileDown, Trash2, Terminal, Filter, Play, Pause, Info, Copy } from 'lucide-react';
|
||||
import { WindowDragRegion } from './WindowDragRegion';
|
||||
@@ -24,6 +25,7 @@ export default function LogsView() {
|
||||
const [levelFilter, setLevelFilter] = useState<LogEntry['level'] | 'All'>('All');
|
||||
const [contextMenu, setContextMenu] = useState<{ x: number; y: number; text: string } | null>(null);
|
||||
const [pageVisible, setPageVisible] = useState(() => document.visibilityState !== 'hidden');
|
||||
const homeDirectoryRef = useRef('');
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
const liveBatchRef = useRef<LogEntry[]>([]);
|
||||
const liveFrameRef = useRef<number | null>(null);
|
||||
@@ -33,6 +35,18 @@ export default function LogsView() {
|
||||
const [isClearing, setIsClearing] = useState(false);
|
||||
const [isToggling, setIsToggling] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
void homeDir()
|
||||
.then(directory => {
|
||||
if (active) homeDirectoryRef.current = directory;
|
||||
})
|
||||
.catch(() => undefined);
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const handleVisibilityChange = () => setPageVisible(document.visibilityState !== 'hidden');
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
@@ -80,7 +94,7 @@ export default function LogsView() {
|
||||
if (logsEnabled) {
|
||||
unlistenPromise = attachLogger((log) => {
|
||||
if (!active) return;
|
||||
scheduleLiveEntry(liveLogEntry(log.level, log.message));
|
||||
scheduleLiveEntry(liveLogEntry(log.level, log.message, new Date(), homeDirectoryRef.current));
|
||||
});
|
||||
await unlistenPromise;
|
||||
if (!active) return;
|
||||
@@ -93,7 +107,7 @@ export default function LogsView() {
|
||||
|
||||
const lines = await invoke('read_logs', { limit: MAX_LOG_LINES });
|
||||
if (!active) return;
|
||||
const snapshot = lines.map(persistedLogEntry);
|
||||
const snapshot = lines.map(line => persistedLogEntry(line, homeDirectoryRef.current));
|
||||
initialized = true;
|
||||
if (initGeneration !== clearGenerationRef.current) {
|
||||
pendingLiveEntries = [];
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
} from '../utils/downloadLocations';
|
||||
import { usePlatformInfo } from '../utils/platform';
|
||||
import { isTrustedFirelinkReleaseUrl } from '../utils/releaseUrls';
|
||||
import { normalizeCustomProxy } from '../store/useDownloadStore';
|
||||
|
||||
const settingsTabs: { type: SettingsTab; label: string; icon: typeof Download }[] = [
|
||||
{ type: 'downloads', label: 'Downloads', icon: Download },
|
||||
@@ -76,6 +77,8 @@ type ManualUpdateStatus =
|
||||
| { type: 'update-available'; version: string; releaseUrl: string }
|
||||
| { type: 'error'; message: string };
|
||||
|
||||
type SystemProxyStatus = 'idle' | 'checking' | 'detected' | 'none' | 'error';
|
||||
|
||||
const engineStatusCache = new Map<string, EngineStatusItem>();
|
||||
const engineStatusInFlight = new Map<string, Promise<EngineStatusItem>>();
|
||||
|
||||
@@ -276,8 +279,9 @@ const [engineStatus, setEngineStatus] = useState<EngineStatusItem[] | null>(null
|
||||
const [expandedEngine, setExpandedEngine] = useState<string | null>(null);
|
||||
const [isRecheckingEngines, setIsRecheckingEngines] = useState(false);
|
||||
const engineRunId = useRef(0);
|
||||
const [appVersion, setAppVersion] = useState('Unknown');
|
||||
const [extensionServerPort, setExtensionServerPort] = useState<number | null>(null);
|
||||
const [appVersion, setAppVersion] = useState('Unknown');
|
||||
const [extensionServerPort, setExtensionServerPort] = useState<number | null>(null);
|
||||
const [systemProxyStatus, setSystemProxyStatus] = useState<SystemProxyStatus>('idle');
|
||||
|
||||
// Local state for adding site login
|
||||
const [loginPattern, setLoginPattern] = useState('');
|
||||
@@ -320,6 +324,27 @@ useEffect(() => {
|
||||
};
|
||||
}, [settings.activeView, activeTab]);
|
||||
|
||||
useEffect(() => {
|
||||
if (settings.activeView !== 'settings' || activeTab !== 'network' || settings.proxyMode !== 'system') {
|
||||
setSystemProxyStatus('idle');
|
||||
return;
|
||||
}
|
||||
|
||||
let active = true;
|
||||
setSystemProxyStatus('checking');
|
||||
invoke('get_system_proxy')
|
||||
.then(proxy => {
|
||||
if (active) setSystemProxyStatus(typeof proxy === 'string' && proxy.trim() ? 'detected' : 'none');
|
||||
})
|
||||
.catch(() => {
|
||||
if (active) setSystemProxyStatus('error');
|
||||
});
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [settings.activeView, settings.proxyMode, activeTab]);
|
||||
|
||||
const runEngineChecks = useCallback((force = false) => {
|
||||
const runId = ++engineRunId.current;
|
||||
const cached = engineChecks
|
||||
@@ -880,10 +905,20 @@ runEngineChecks(false);
|
||||
<p className="settings-group-footer">
|
||||
{settings.proxyMode === 'none' && 'Downloads ignore configured proxies.'}
|
||||
{settings.proxyMode === 'system' && `Downloads use the detected ${platform.os === 'macos' ? 'macOS' : platform.os === 'windows' ? 'Windows' : 'desktop'} system proxy. Normal file downloads require an HTTP or HTTPS proxy endpoint; media downloads can use SOCKS.`}
|
||||
{settings.proxyMode === 'custom' && (settings.proxyHost
|
||||
{settings.proxyMode === 'custom' && (normalizeCustomProxy(settings.proxyHost, settings.proxyPort)
|
||||
? 'Downloads use the configured HTTP proxy endpoint for metadata and download engines.'
|
||||
: 'Enter a proxy host and port to enable the custom proxy.')}
|
||||
: settings.proxyHost
|
||||
? 'Enter a valid HTTP proxy host and port to enable the custom proxy.'
|
||||
: 'Enter a proxy host and port to enable the custom proxy.')}
|
||||
</p>
|
||||
{settings.proxyMode === 'system' && (
|
||||
<p className="settings-group-footer" role="status">
|
||||
{systemProxyStatus === 'checking' && 'Checking system proxy configuration…'}
|
||||
{systemProxyStatus === 'detected' && 'A system proxy was detected. Normal file downloads require an HTTP or HTTPS endpoint; media downloads can use SOCKS.'}
|
||||
{systemProxyStatus === 'none' && 'No usable system proxy was detected. Downloads will use no proxy.'}
|
||||
{systemProxyStatus === 'error' && 'System proxy configuration could not be read. Downloads will use no proxy until it is available.'}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<h2 className="settings-section-title">Identity</h2>
|
||||
|
||||
Reference in New Issue
Block a user