From 1a7a2a0bfce2e6540cb46f38363c9071d9a53a6e Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Thu, 21 May 2026 22:43:46 +0200 Subject: [PATCH] chore(servers): remove quick/full scan buttons from server cards (#843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops the Quick/Full scan actions and all supporting logic — they are no longer needed. Removes the ServerScanActions component (incl. the unused compact variant), the subsonicScan API, the scanStore, and the app-root useScanPolling hook (no more background scan polling). Cleans up the .server-scan-* CSS and the settings.scan i18n block across all 9 locales. 440 deletions, no new code; tsc + bundle clean. --- src/api/subsonicScan.ts | 23 --- src/app/MainApp.tsx | 3 - src/components/settings/ServerScanActions.tsx | 164 ------------------ src/components/settings/ServersTab.tsx | 2 - src/hooks/useScanPolling.ts | 64 ------- src/locales/de/settings.ts | 12 -- src/locales/en/settings.ts | 12 -- src/locales/es/settings.ts | 12 -- src/locales/fr/settings.ts | 12 -- src/locales/nb/settings.ts | 12 -- src/locales/nl/settings.ts | 12 -- src/locales/ro/settings.ts | 12 -- src/locales/ru/settings.ts | 12 -- src/locales/zh/settings.ts | 12 -- src/store/scanStore.ts | 33 ---- .../components/connection-indicator.css | 43 ----- 16 files changed, 440 deletions(-) delete mode 100644 src/api/subsonicScan.ts delete mode 100644 src/components/settings/ServerScanActions.tsx delete mode 100644 src/hooks/useScanPolling.ts delete mode 100644 src/store/scanStore.ts diff --git a/src/api/subsonicScan.ts b/src/api/subsonicScan.ts deleted file mode 100644 index eedbf57e..00000000 --- a/src/api/subsonicScan.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { apiForServer } from './subsonicClient'; - -export interface ScanStatus { - scanning: boolean; - count: number; - folderCount?: number; - lastScan?: string; -} - -export async function startScan(serverId: string, fullScan: boolean): Promise { - await apiForServer(serverId, 'startScan.view', fullScan ? { fullScan: 'true' } : {}, 10000); -} - -export async function getScanStatus(serverId: string): Promise { - const data = await apiForServer<{ scanStatus?: ScanStatus }>(serverId, 'getScanStatus.view', {}, 8000); - const s = data.scanStatus; - return { - scanning: !!s?.scanning, - count: typeof s?.count === 'number' ? s.count : 0, - folderCount: typeof s?.folderCount === 'number' ? s.folderCount : undefined, - lastScan: typeof s?.lastScan === 'string' ? s.lastScan : undefined, - }; -} diff --git a/src/app/MainApp.tsx b/src/app/MainApp.tsx index 48729df8..57987d68 100644 --- a/src/app/MainApp.tsx +++ b/src/app/MainApp.tsx @@ -14,7 +14,6 @@ import { useGlobalShortcutsStore } from '../store/globalShortcutsStore'; import { initHotCachePrefetch } from '../hotCachePrefetch'; import { initMiniPlayerBridgeOnMain } from '../utils/miniPlayerBridge'; import { runAdvancedModeMigration } from '../utils/migrations/advancedModeMigration'; -import { useScanPolling } from '../hooks/useScanPolling'; import { IS_WINDOWS } from '../utils/platform'; import TauriEventBridge from './TauriEventBridge'; import AppShell from './AppShell'; @@ -35,8 +34,6 @@ export default function MainApp() { // Advanced Mode toggle. Idempotent — flagged in localStorage. useEffect(() => { runAdvancedModeMigration(); }, []); - useScanPolling(); - // Push playback state to mini window + handle control events. useEffect(() => { return initMiniPlayerBridgeOnMain(); diff --git a/src/components/settings/ServerScanActions.tsx b/src/components/settings/ServerScanActions.tsx deleted file mode 100644 index 115b127d..00000000 --- a/src/components/settings/ServerScanActions.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import React, { useEffect, useRef } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Check, DatabaseZap, Loader2, RefreshCw, WifiOff } from 'lucide-react'; -import { startScan } from '../../api/subsonicScan'; -import { useScanStore } from '../../store/scanStore'; -import { showToast } from '../../utils/ui/toast'; - -const CONFIRM_TIMEOUT_MS = 3000; - -interface Props { - serverId: string; - /** `compact` for the server switcher dropdown (icon-only), `card` for the settings cards. */ - variant: 'compact' | 'card'; -} - -export default function ServerScanActions({ serverId, variant }: Props) { - const { t } = useTranslation(); - const entry = useScanStore(s => s.byServer[serverId]); - const setEntry = useScanStore(s => s.set); - const confirmTimerRef = useRef | null>(null); - - const phase = entry?.phase ?? 'idle'; - const count = entry?.count ?? 0; - const confirmingFull = entry?.confirmingFull ?? false; - const busy = phase === 'starting' || phase === 'running'; - - useEffect(() => () => { - if (confirmTimerRef.current) clearTimeout(confirmTimerRef.current); - }, []); - - const armConfirmTimeout = () => { - if (confirmTimerRef.current) clearTimeout(confirmTimerRef.current); - confirmTimerRef.current = setTimeout(() => { - setEntry(serverId, { confirmingFull: false }); - }, CONFIRM_TIMEOUT_MS); - }; - - const launch = async (full: boolean) => { - setEntry(serverId, { phase: 'starting', type: full ? 'full' : 'quick', count: 0, confirmingFull: false }); - try { - await startScan(serverId, full); - setEntry(serverId, { phase: 'running' }); - } catch (err) { - setEntry(serverId, { phase: 'error' }); - showToast(typeof err === 'string' ? err : err instanceof Error ? err.message : 'Scan failed', 4000, 'error'); - } - }; - - const onQuickClick = (e: React.MouseEvent) => { - e.stopPropagation(); - if (busy) return; - void launch(false); - }; - - const onFullClick = (e: React.MouseEvent) => { - e.stopPropagation(); - if (busy) return; - if (!confirmingFull) { - setEntry(serverId, { confirmingFull: true }); - armConfirmTimeout(); - return; - } - if (confirmTimerRef.current) clearTimeout(confirmTimerRef.current); - void launch(true); - }; - - // ── Status slot content ────────────────────────────────────────────────── - const status = (() => { - if (phase === 'running' || phase === 'starting') { - const label = count > 0 ? formatCount(count) : ''; - return ( - - - {label && {label}} - - ); - } - if (phase === 'just-finished') { - return ( - - - - ); - } - if (phase === 'error') { - return ( - - - - ); - } - return null; - })(); - - // ── Render ─────────────────────────────────────────────────────────────── - if (variant === 'compact') { - return ( - e.stopPropagation()}> - - - {status} - - ); - } - - // Card variant — matches the existing `btn btn-surface` chrome in ServersTab actions. - return ( - <> - - - {status && {status}} - - ); -} - -function formatCount(n: number): string { - if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`; - if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`; - return String(n); -} diff --git a/src/components/settings/ServersTab.tsx b/src/components/settings/ServersTab.tsx index cac940c1..f4654ce0 100644 --- a/src/components/settings/ServersTab.tsx +++ b/src/components/settings/ServersTab.tsx @@ -13,7 +13,6 @@ import { serverListDisplayLabel } from '../../utils/server/serverDisplayName'; import { switchActiveServer } from '../../utils/server/switchActiveServer'; import { AddServerForm } from './AddServerForm'; import { ServerGripHandle } from './ServerGripHandle'; -import ServerScanActions from './ServerScanActions'; const AUDIOMUSE_NV_PLUGIN_URL = 'https://github.com/NeptuneHub/AudioMuse-AI-NV-plugin'; @@ -277,7 +276,6 @@ export function ServersTab({ {status === 'ok' && } {status === 'error' && } {status === 'testing' &&
} -