diff --git a/src/app/AppRoutes.tsx b/src/app/AppRoutes.tsx index ab7b5205..e36a5539 100644 --- a/src/app/AppRoutes.tsx +++ b/src/app/AppRoutes.tsx @@ -2,10 +2,10 @@ import { lazy } from 'react'; import { Navigate, Route, Routes } from 'react-router-dom'; import MobilePlayerView from '../components/MobilePlayerView'; import { useIsMobile } from '../hooks/useIsMobile'; -import { useSidebarStore } from '../store/sidebarStore'; +import { useSidebarStore } from '@/features/sidebar'; import { useAuthStore } from '../store/authStore'; import { useLuckyMixAvailable } from '../hooks/useLuckyMixAvailable'; -import { resolveStartRoute } from '../utils/componentHelpers/sidebarNavReorder'; +import { resolveStartRoute } from '@/features/sidebar'; // Route-level lazy loading: keeps the non-page graph (shell, player, stores) in // the entry chunk; each page is fetched when its route is first visited. diff --git a/src/app/AppShell.tsx b/src/app/AppShell.tsx index abad825e..6ccd55c7 100644 --- a/src/app/AppShell.tsx +++ b/src/app/AppShell.tsx @@ -5,7 +5,7 @@ import { navigatePathWithAlbumReturnTo, shouldSkipMainScrollResetOnRouteChange } import { getCurrentWebview } from '@tauri-apps/api/webview'; import { PanelRight } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import Sidebar from '../components/Sidebar'; +import Sidebar from '@/features/sidebar'; import PlayerBar from '../components/PlayerBar'; import BottomNav from '../components/BottomNav'; import { useIsMobile } from '../hooks/useIsMobile'; diff --git a/src/components/MobileMoreOverlay.tsx b/src/components/MobileMoreOverlay.tsx index a21f9060..17f08b74 100644 --- a/src/components/MobileMoreOverlay.tsx +++ b/src/components/MobileMoreOverlay.tsx @@ -2,7 +2,7 @@ import { createPortal } from 'react-dom'; import { NavLink } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Settings, HardDriveDownload } from 'lucide-react'; -import { useSidebarStore } from '../store/sidebarStore'; +import { useSidebarStore } from '@/features/sidebar'; import { useAuthStore } from '../store/authStore'; import { ALL_NAV_ITEMS } from '../config/navItems'; import { useLuckyMixAvailable } from '../hooks/useLuckyMixAvailable'; diff --git a/src/components/settings/PersonalisationTab.tsx b/src/components/settings/PersonalisationTab.tsx index 28971487..c7864f21 100644 --- a/src/components/settings/PersonalisationTab.tsx +++ b/src/components/settings/PersonalisationTab.tsx @@ -7,7 +7,7 @@ import { useHomeStore } from '../../store/homeStore'; import { usePlayerBarLayoutStore } from '../../store/playerBarLayoutStore'; import { usePlaylistLayoutStore } from '../../store/playlistLayoutStore'; import { useQueueToolbarStore } from '../../store/queueToolbarStore'; -import { useSidebarStore } from '../../store/sidebarStore'; +import { useSidebarStore } from '@/features/sidebar'; import SettingsSubSection from '../SettingsSubSection'; import { SettingsGroup } from './SettingsGroup'; import { SettingsToggle } from './SettingsToggle'; diff --git a/src/components/settings/SidebarCustomizer.tsx b/src/components/settings/SidebarCustomizer.tsx index c4bc1864..bad5cc30 100644 --- a/src/components/settings/SidebarCustomizer.tsx +++ b/src/components/settings/SidebarCustomizer.tsx @@ -1,10 +1,10 @@ import { useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useAuthStore } from '../../store/authStore'; -import { useSidebarStore, SidebarItemConfig, CONSERVED_SIDEBAR_NAV_IDS } from '../../store/sidebarStore'; +import { useSidebarStore, SidebarItemConfig, CONSERVED_SIDEBAR_NAV_IDS } from '@/features/sidebar'; import { useLuckyMixAvailable } from '../../hooks/useLuckyMixAvailable'; import { ALL_NAV_ITEMS } from '../../config/navItems'; -import { applySidebarReorderById } from '../../utils/componentHelpers/sidebarNavReorder'; +import { applySidebarReorderById } from '@/features/sidebar'; import { useListReorderDnd } from '../../hooks/useListReorderDnd'; import type { ListReorderDropTarget } from '../../utils/componentHelpers/listReorder'; import { ReorderGripHandle } from './ReorderGripHandle'; diff --git a/src/components/Sidebar.tsx b/src/features/sidebar/components/Sidebar.tsx similarity index 87% rename from src/components/Sidebar.tsx rename to src/features/sidebar/components/Sidebar.tsx index f29e9029..3decb2f2 100644 --- a/src/components/Sidebar.tsx +++ b/src/features/sidebar/components/Sidebar.tsx @@ -1,34 +1,34 @@ import { useState, useRef, useEffect, useMemo } from 'react'; import { createPortal } from 'react-dom'; -import { usePlayerStore } from '../store/playerStore'; -import { useOfflineJobStore } from '../store/offlineJobStore'; -import { clearOfflinePinTasks } from '../utils/offline/offlinePinQueue'; +import { usePlayerStore } from '@/store/playerStore'; +import { useOfflineJobStore } from '@/store/offlineJobStore'; +import { clearOfflinePinTasks } from '@/utils/offline/offlinePinQueue'; import { useDeviceSyncJobStore } from '@/features/deviceSync'; -import { useAuthStore } from '../store/authStore'; -import { useSidebarStore } from '../store/sidebarStore'; +import { useAuthStore } from '@/store/authStore'; +import { useSidebarStore } from '@/features/sidebar/store/sidebarStore'; import { useLocation } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { PanelLeft, PanelLeftClose, Trash2 } from 'lucide-react'; -import PsysonicLogo from './PsysonicLogo'; -import PSmallLogo from './PSmallLogo'; -import { usePlaylistStore } from '../store/playlistStore'; +import PsysonicLogo from '@/components/PsysonicLogo'; +import PSmallLogo from '@/components/PSmallLogo'; +import { usePlaylistStore } from '@/store/playlistStore'; import OverlayScrollArea from '@/ui/OverlayScrollArea'; import { getLibraryItemsForReorder, getSystemItemsForReorder, -} from '../utils/componentHelpers/sidebarNavReorder'; -import { useLuckyMixAvailable } from '../hooks/useLuckyMixAvailable'; -import { usePerfProbeFlags } from '../utils/perf/perfFlags'; -import { useSidebarNewReleasesUnread } from '../hooks/useSidebarNewReleasesUnread'; -import { useSidebarNavDnd } from '../hooks/useSidebarNavDnd'; -import { useSidebarLibraryDropdown } from '../hooks/useSidebarLibraryDropdown'; -import { useSidebarScrollVisible } from '../hooks/useSidebarScrollVisible'; -import { isOfflineSidebarNavAllowed } from '../utils/offline/offlineNavPolicy'; -import { useOfflineBrowseContext } from '../hooks/useOfflineBrowseContext'; -import { offlineBrowseNavFlags } from '../utils/offline/offlineBrowseContext'; -import { useSidebarPerfProbe } from '../hooks/useSidebarPerfProbe'; -import SidebarPerfProbeModal from './sidebar/SidebarPerfProbeModal'; -import SidebarNavBody from './sidebar/SidebarNavBody'; +} from '@/features/sidebar/utils/sidebarNavReorder'; +import { useLuckyMixAvailable } from '@/hooks/useLuckyMixAvailable'; +import { usePerfProbeFlags } from '@/utils/perf/perfFlags'; +import { useSidebarNewReleasesUnread } from '@/features/sidebar/hooks/useSidebarNewReleasesUnread'; +import { useSidebarNavDnd } from '@/features/sidebar/hooks/useSidebarNavDnd'; +import { useSidebarLibraryDropdown } from '@/features/sidebar/hooks/useSidebarLibraryDropdown'; +import { useSidebarScrollVisible } from '@/features/sidebar/hooks/useSidebarScrollVisible'; +import { isOfflineSidebarNavAllowed } from '@/utils/offline/offlineNavPolicy'; +import { useOfflineBrowseContext } from '@/hooks/useOfflineBrowseContext'; +import { offlineBrowseNavFlags } from '@/utils/offline/offlineBrowseContext'; +import { useSidebarPerfProbe } from '@/features/sidebar/hooks/useSidebarPerfProbe'; +import SidebarPerfProbeModal from '@/features/sidebar/components/SidebarPerfProbeModal'; +import SidebarNavBody from '@/features/sidebar/components/SidebarNavBody'; export default function Sidebar({ diff --git a/src/components/sidebar/SidebarActiveJobs.tsx b/src/features/sidebar/components/SidebarActiveJobs.tsx similarity index 100% rename from src/components/sidebar/SidebarActiveJobs.tsx rename to src/features/sidebar/components/SidebarActiveJobs.tsx diff --git a/src/components/sidebar/SidebarLibraryPicker.tsx b/src/features/sidebar/components/SidebarLibraryPicker.tsx similarity index 100% rename from src/components/sidebar/SidebarLibraryPicker.tsx rename to src/features/sidebar/components/SidebarLibraryPicker.tsx diff --git a/src/components/sidebar/SidebarNavBody.tsx b/src/features/sidebar/components/SidebarNavBody.tsx similarity index 95% rename from src/components/sidebar/SidebarNavBody.tsx rename to src/features/sidebar/components/SidebarNavBody.tsx index d7fd7862..c69f8b66 100644 --- a/src/components/sidebar/SidebarNavBody.tsx +++ b/src/features/sidebar/components/SidebarNavBody.tsx @@ -2,13 +2,13 @@ import React from 'react'; import { NavLink } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { AudioLines, ChevronRight, HardDriveDownload, Settings } from 'lucide-react'; -import type { SidebarItemConfig } from '../../store/sidebarStore'; -import { ALL_NAV_ITEMS } from '../../config/navItems'; -import WhatsNewBanner from '../WhatsNewBanner'; -import ThemeUpdateBanner from '../ThemeUpdateBanner'; -import SidebarLibraryPicker from './SidebarLibraryPicker'; -import SidebarPlaylistsSection from './SidebarPlaylistsSection'; -import SidebarActiveJobs from './SidebarActiveJobs'; +import type { SidebarItemConfig } from '@/features/sidebar/store/sidebarStore'; +import { ALL_NAV_ITEMS } from '@/config/navItems'; +import WhatsNewBanner from '@/components/WhatsNewBanner'; +import ThemeUpdateBanner from '@/components/ThemeUpdateBanner'; +import SidebarLibraryPicker from '@/features/sidebar/components/SidebarLibraryPicker'; +import SidebarPlaylistsSection from '@/features/sidebar/components/SidebarPlaylistsSection'; +import SidebarActiveJobs from '@/features/sidebar/components/SidebarActiveJobs'; interface NavDndState { section: 'library' | 'system'; diff --git a/src/components/sidebar/SidebarPerfProbeModal.tsx b/src/features/sidebar/components/SidebarPerfProbeModal.tsx similarity index 85% rename from src/components/sidebar/SidebarPerfProbeModal.tsx rename to src/features/sidebar/components/SidebarPerfProbeModal.tsx index 806b27eb..e10cddd1 100644 --- a/src/components/sidebar/SidebarPerfProbeModal.tsx +++ b/src/features/sidebar/components/SidebarPerfProbeModal.tsx @@ -1,15 +1,15 @@ import { useState } from 'react'; import { Activity, Network, ScrollText, SlidersHorizontal, Wrench, X } from 'lucide-react'; import { createPortal } from 'react-dom'; -import SidebarPerfProbeMonitorTab from './perfProbe/SidebarPerfProbeMonitorTab'; -import SidebarPerfProbeTogglesTab from './perfProbe/SidebarPerfProbeTogglesTab'; -import SidebarPerfProbeTuningTab from './perfProbe/SidebarPerfProbeTuningTab'; -import SidebarPerfProbeLogsTab from './perfProbe/SidebarPerfProbeLogsTab'; -import SidebarPerfProbeConnectionsTab from './perfProbe/SidebarPerfProbeConnectionsTab'; -import { resetPerfProbeFlags, type PerfProbeFlags } from '../../utils/perf/perfFlags'; -import { clearPerfLiveOverlayPins } from '../../utils/perf/perfOverlayPins'; -import { resetPerfOverlayAppearance } from '../../utils/perf/perfOverlayAppearance'; -import { resetPerfOverlayMode } from '../../utils/perf/perfOverlayMode'; +import SidebarPerfProbeMonitorTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeMonitorTab'; +import SidebarPerfProbeTogglesTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeTogglesTab'; +import SidebarPerfProbeTuningTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeTuningTab'; +import SidebarPerfProbeLogsTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeLogsTab'; +import SidebarPerfProbeConnectionsTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeConnectionsTab'; +import { resetPerfProbeFlags, type PerfProbeFlags } from '@/utils/perf/perfFlags'; +import { clearPerfLiveOverlayPins } from '@/utils/perf/perfOverlayPins'; +import { resetPerfOverlayAppearance } from '@/utils/perf/perfOverlayAppearance'; +import { resetPerfOverlayMode } from '@/utils/perf/perfOverlayMode'; type TabId = 'monitor' | 'connections' | 'toggles' | 'tuning' | 'logs'; diff --git a/src/components/sidebar/SidebarPlaylistsSection.tsx b/src/features/sidebar/components/SidebarPlaylistsSection.tsx similarity index 88% rename from src/components/sidebar/SidebarPlaylistsSection.tsx rename to src/features/sidebar/components/SidebarPlaylistsSection.tsx index cdc5fb23..ae3d9d53 100644 --- a/src/components/sidebar/SidebarPlaylistsSection.tsx +++ b/src/features/sidebar/components/SidebarPlaylistsSection.tsx @@ -2,12 +2,12 @@ import React from 'react'; import { NavLink } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { ChevronRight, Folder, PlayCircle, Sparkles } from 'lucide-react'; -import { displayPlaylistName, isSmartPlaylistName } from '../../utils/componentHelpers/sidebarHelpers'; -import { useAuthStore } from '../../store/authStore'; -import { usePlayerStore } from '../../store/playerStore'; -import { usePlaylistStore } from '../../store/playlistStore'; -import { EMPTY_SERVER_FOLDERS, usePlaylistFolderStore } from '../../store/playlistFolderStore'; -import { groupPlaylistsByFolder } from '../../utils/playlist/playlistFolders'; +import { displayPlaylistName, isSmartPlaylistName } from '@/features/sidebar/utils/sidebarHelpers'; +import { useAuthStore } from '@/store/authStore'; +import { usePlayerStore } from '@/store/playerStore'; +import { usePlaylistStore } from '@/store/playlistStore'; +import { EMPTY_SERVER_FOLDERS, usePlaylistFolderStore } from '@/store/playlistFolderStore'; +import { groupPlaylistsByFolder } from '@/utils/playlist/playlistFolders'; interface SidebarPlaylist { id: string; diff --git a/src/components/sidebar/perfProbe/PerfCoverThreadsControl.tsx b/src/features/sidebar/components/perfProbe/PerfCoverThreadsControl.tsx similarity index 98% rename from src/components/sidebar/perfProbe/PerfCoverThreadsControl.tsx rename to src/features/sidebar/components/perfProbe/PerfCoverThreadsControl.tsx index b2683251..dffc799d 100644 --- a/src/components/sidebar/perfProbe/PerfCoverThreadsControl.tsx +++ b/src/features/sidebar/components/perfProbe/PerfCoverThreadsControl.tsx @@ -4,7 +4,7 @@ import { libraryCoverBackfillResetCursor, libraryCoverBackfillRunFullPass, libraryCoverBackfillSetParallel, -} from '../../../api/coverCache'; +} from '@/api/coverCache'; const COVER_THREADS_MIN = 1; const COVER_THREADS_MAX = 16; diff --git a/src/components/sidebar/perfProbe/PerfLivePollControls.tsx b/src/features/sidebar/components/perfProbe/PerfLivePollControls.tsx similarity index 92% rename from src/components/sidebar/perfProbe/PerfLivePollControls.tsx rename to src/features/sidebar/components/perfProbe/PerfLivePollControls.tsx index fe7bf26e..a71aa8a5 100644 --- a/src/components/sidebar/perfProbe/PerfLivePollControls.tsx +++ b/src/features/sidebar/components/perfProbe/PerfLivePollControls.tsx @@ -1,4 +1,4 @@ -import { perfLiveCpuSnapshotSupported } from '../../../utils/perf/perfLiveCpuSnapshot'; +import { perfLiveCpuSnapshotSupported } from '@/utils/perf/perfLiveCpuSnapshot'; import { PERF_LIVE_POLL_MS_MAX, PERF_LIVE_POLL_MS_MIN, @@ -7,7 +7,7 @@ import { setPerfLivePollIntervalMs, usePerfLiveIncludeThreadGroups, usePerfLivePollIntervalMs, -} from '../../../utils/perf/perfLivePollSettings'; +} from '@/utils/perf/perfLivePollSettings'; export default function PerfLivePollControls() { const pollMs = usePerfLivePollIntervalMs(); diff --git a/src/components/sidebar/perfProbe/PerfOverlayAppearanceControls.tsx b/src/features/sidebar/components/perfProbe/PerfOverlayAppearanceControls.tsx similarity index 97% rename from src/components/sidebar/perfProbe/PerfOverlayAppearanceControls.tsx rename to src/features/sidebar/components/perfProbe/PerfOverlayAppearanceControls.tsx index 62a03291..aed1aca5 100644 --- a/src/components/sidebar/perfProbe/PerfOverlayAppearanceControls.tsx +++ b/src/features/sidebar/components/perfProbe/PerfOverlayAppearanceControls.tsx @@ -3,7 +3,7 @@ import { setPerfOverlayCorner, setPerfOverlayOpacity, usePerfOverlayAppearance, -} from '../../../utils/perf/perfOverlayAppearance'; +} from '@/utils/perf/perfOverlayAppearance'; export default function PerfOverlayAppearanceControls() { const { corner, opacity } = usePerfOverlayAppearance(); diff --git a/src/components/sidebar/perfProbe/PerfOverlayModeControls.tsx b/src/features/sidebar/components/perfProbe/PerfOverlayModeControls.tsx similarity index 96% rename from src/components/sidebar/perfProbe/PerfOverlayModeControls.tsx rename to src/features/sidebar/components/perfProbe/PerfOverlayModeControls.tsx index 74be0a0f..ee39832e 100644 --- a/src/components/sidebar/perfProbe/PerfOverlayModeControls.tsx +++ b/src/features/sidebar/components/perfProbe/PerfOverlayModeControls.tsx @@ -2,7 +2,7 @@ import { PERF_OVERLAY_MODE_OPTIONS, setPerfOverlayMode, usePerfOverlayMode, -} from '../../../utils/perf/perfOverlayMode'; +} from '@/utils/perf/perfOverlayMode'; export default function PerfOverlayModeControls() { const mode = usePerfOverlayMode(); diff --git a/src/components/sidebar/perfProbe/PerfProbeDetailList.tsx b/src/features/sidebar/components/perfProbe/PerfProbeDetailList.tsx similarity index 100% rename from src/components/sidebar/perfProbe/PerfProbeDetailList.tsx rename to src/features/sidebar/components/perfProbe/PerfProbeDetailList.tsx diff --git a/src/components/sidebar/perfProbe/PerfProbeMetricCard.tsx b/src/features/sidebar/components/perfProbe/PerfProbeMetricCard.tsx similarity index 100% rename from src/components/sidebar/perfProbe/PerfProbeMetricCard.tsx rename to src/features/sidebar/components/perfProbe/PerfProbeMetricCard.tsx diff --git a/src/components/sidebar/perfProbe/PerfProbeStatusBadge.tsx b/src/features/sidebar/components/perfProbe/PerfProbeStatusBadge.tsx similarity index 100% rename from src/components/sidebar/perfProbe/PerfProbeStatusBadge.tsx rename to src/features/sidebar/components/perfProbe/PerfProbeStatusBadge.tsx diff --git a/src/components/sidebar/perfProbe/SidebarPerfProbeConnectionsTab.tsx b/src/features/sidebar/components/perfProbe/SidebarPerfProbeConnectionsTab.tsx similarity index 85% rename from src/components/sidebar/perfProbe/SidebarPerfProbeConnectionsTab.tsx rename to src/features/sidebar/components/perfProbe/SidebarPerfProbeConnectionsTab.tsx index ff5cb10c..c954af09 100644 --- a/src/components/sidebar/perfProbe/SidebarPerfProbeConnectionsTab.tsx +++ b/src/features/sidebar/components/perfProbe/SidebarPerfProbeConnectionsTab.tsx @@ -1,13 +1,13 @@ -import { useAuthStore } from '../../../store/authStore'; -import { usePlayerStore } from '../../../store/playerStore'; -import { useConnectionStatus } from '../../../hooks/useConnectionStatus'; -import { useNavidromeAdminRole } from '../../../hooks/useNavidromeAdminRole'; -import { serverListDisplayLabel } from '../../../utils/server/serverDisplayName'; -import { findServerByIdOrIndexKey } from '../../../utils/server/serverLookup'; -import { PerfProbeMetricSection } from './PerfProbeMetricCard'; -import PerfProbeDetailList from './PerfProbeDetailList'; -import PerfProbeStatusBadge, { type PerfProbeBadgeTone } from './PerfProbeStatusBadge'; -import SidebarPerfProbeServerSection from './SidebarPerfProbeServerSection'; +import { useAuthStore } from '@/store/authStore'; +import { usePlayerStore } from '@/store/playerStore'; +import { useConnectionStatus } from '@/hooks/useConnectionStatus'; +import { useNavidromeAdminRole } from '@/hooks/useNavidromeAdminRole'; +import { serverListDisplayLabel } from '@/utils/server/serverDisplayName'; +import { findServerByIdOrIndexKey } from '@/utils/server/serverLookup'; +import { PerfProbeMetricSection } from '@/features/sidebar/components/perfProbe/PerfProbeMetricCard'; +import PerfProbeDetailList from '@/features/sidebar/components/perfProbe/PerfProbeDetailList'; +import PerfProbeStatusBadge, { type PerfProbeBadgeTone } from '@/features/sidebar/components/perfProbe/PerfProbeStatusBadge'; +import SidebarPerfProbeServerSection from '@/features/sidebar/components/perfProbe/SidebarPerfProbeServerSection'; function connectionStatusBadge(status: string): { tone: PerfProbeBadgeTone; label: string } { switch (status) { diff --git a/src/components/sidebar/perfProbe/SidebarPerfProbeLogsTab.tsx b/src/features/sidebar/components/perfProbe/SidebarPerfProbeLogsTab.tsx similarity index 97% rename from src/components/sidebar/perfProbe/SidebarPerfProbeLogsTab.tsx rename to src/features/sidebar/components/perfProbe/SidebarPerfProbeLogsTab.tsx index 13bbf43e..c55617ab 100644 --- a/src/components/sidebar/perfProbe/SidebarPerfProbeLogsTab.tsx +++ b/src/features/sidebar/components/perfProbe/SidebarPerfProbeLogsTab.tsx @@ -11,13 +11,13 @@ import { Copy, Download, Pause, Play, Trash2 } from 'lucide-react'; import { createPortal } from 'react-dom'; import { save as saveDialog } from '@tauri-apps/plugin-dialog'; import { writeFile } from '@tauri-apps/plugin-fs'; -import { getLoggingMode, tailRuntimeLogs, type RuntimeLogLine } from '../../../api/runtimeLogs'; +import { getLoggingMode, tailRuntimeLogs, type RuntimeLogLine } from '@/api/runtimeLogs'; import { invoke } from '@tauri-apps/api/core'; -import { useAuthStore } from '../../../store/authStore'; -import type { LoggingMode } from '../../../store/authStoreTypes'; +import { useAuthStore } from '@/store/authStore'; +import type { LoggingMode } from '@/store/authStoreTypes'; import CustomSelect from '@/ui/CustomSelect'; -import { filterLogLines } from '../../../utils/perf/filterLogLines'; -import { sanitizeLogLine } from '../../../utils/perf/sanitizeLogLine'; +import { filterLogLines } from '@/utils/perf/filterLogLines'; +import { sanitizeLogLine } from '@/utils/perf/sanitizeLogLine'; function formatLogLinesText(lines: RuntimeLogLine[]): string { return lines.map(line => line.text).join('\n'); diff --git a/src/components/sidebar/perfProbe/SidebarPerfProbeMonitorTab.tsx b/src/features/sidebar/components/perfProbe/SidebarPerfProbeMonitorTab.tsx similarity index 94% rename from src/components/sidebar/perfProbe/SidebarPerfProbeMonitorTab.tsx rename to src/features/sidebar/components/perfProbe/SidebarPerfProbeMonitorTab.tsx index 041d45fd..6549f5d3 100644 --- a/src/components/sidebar/perfProbe/SidebarPerfProbeMonitorTab.tsx +++ b/src/features/sidebar/components/perfProbe/SidebarPerfProbeMonitorTab.tsx @@ -1,17 +1,17 @@ import { useMemo, useRef } from 'react'; -import { isPerfLivePollWaitingForCpu, usePerfLiveSnapshot } from '../../../utils/perf/perfLiveStore'; -import { usePerfLiveIncludeThreadGroups } from '../../../utils/perf/perfLivePollSettings'; +import { isPerfLivePollWaitingForCpu, usePerfLiveSnapshot } from '@/utils/perf/perfLiveStore'; +import { usePerfLiveIncludeThreadGroups } from '@/utils/perf/perfLivePollSettings'; import { togglePerfLiveOverlayPin, togglePipelineOverlayPin, usePerfLiveOverlayPins, usePipelineOverlayPinned, type PerfLiveOverlayPinId, -} from '../../../utils/perf/perfOverlayPins'; -import PerfProbeMetricCard, { PerfProbeMetricSection } from './PerfProbeMetricCard'; -import PerfOverlayAppearanceControls from './PerfOverlayAppearanceControls'; -import PerfOverlayModeControls from './PerfOverlayModeControls'; -import PerfLivePollControls from './PerfLivePollControls'; +} from '@/utils/perf/perfOverlayPins'; +import PerfProbeMetricCard, { PerfProbeMetricSection } from '@/features/sidebar/components/perfProbe/PerfProbeMetricCard'; +import PerfOverlayAppearanceControls from '@/features/sidebar/components/perfProbe/PerfOverlayAppearanceControls'; +import PerfOverlayModeControls from '@/features/sidebar/components/perfProbe/PerfOverlayModeControls'; +import PerfLivePollControls from '@/features/sidebar/components/perfProbe/PerfLivePollControls'; function memoryBarPct(rssKb: number, maxKb: number): number { if (maxKb <= 0) return 0; diff --git a/src/components/sidebar/perfProbe/SidebarPerfProbeServerSection.tsx b/src/features/sidebar/components/perfProbe/SidebarPerfProbeServerSection.tsx similarity index 88% rename from src/components/sidebar/perfProbe/SidebarPerfProbeServerSection.tsx rename to src/features/sidebar/components/perfProbe/SidebarPerfProbeServerSection.tsx index 3f4a3979..02b342e8 100644 --- a/src/components/sidebar/perfProbe/SidebarPerfProbeServerSection.tsx +++ b/src/features/sidebar/components/perfProbe/SidebarPerfProbeServerSection.tsx @@ -1,16 +1,16 @@ -import { useAuthStore } from '../../../store/authStore'; -import type { NavidromeAdminRole } from '../../../hooks/useNavidromeAdminRole'; -import { isNavidromeServer, formatServerSoftware } from '../../../utils/server/subsonicServerIdentity'; -import { FEATURE_AUDIOMUSE_SIMILAR_TRACKS, OP_SIMILAR_TRACKS } from '../../../serverCapabilities/catalog'; +import { useAuthStore } from '@/store/authStore'; +import type { NavidromeAdminRole } from '@/hooks/useNavidromeAdminRole'; +import { isNavidromeServer, formatServerSoftware } from '@/utils/server/subsonicServerIdentity'; +import { FEATURE_AUDIOMUSE_SIMILAR_TRACKS, OP_SIMILAR_TRACKS } from '@/serverCapabilities/catalog'; import { isFeatureActiveForServer, resolveCallRoutesForServer, resolveFeatureForServer, -} from '../../../serverCapabilities/storeView'; -import type { CapabilityStatus, FeatureTrust, ResolvedCapability } from '../../../serverCapabilities/types'; -import { PerfProbeMetricSection } from './PerfProbeMetricCard'; -import PerfProbeDetailList, { type PerfProbeDetailRow } from './PerfProbeDetailList'; -import PerfProbeStatusBadge, { type PerfProbeBadgeTone } from './PerfProbeStatusBadge'; +} from '@/serverCapabilities/storeView'; +import type { CapabilityStatus, FeatureTrust, ResolvedCapability } from '@/serverCapabilities/types'; +import { PerfProbeMetricSection } from '@/features/sidebar/components/perfProbe/PerfProbeMetricCard'; +import PerfProbeDetailList, { type PerfProbeDetailRow } from '@/features/sidebar/components/perfProbe/PerfProbeDetailList'; +import PerfProbeStatusBadge, { type PerfProbeBadgeTone } from '@/features/sidebar/components/perfProbe/PerfProbeStatusBadge'; function detectionBadge(status: CapabilityStatus): { tone: PerfProbeBadgeTone; label: string } { switch (status) { diff --git a/src/components/sidebar/perfProbe/SidebarPerfProbeTogglesTab.tsx b/src/features/sidebar/components/perfProbe/SidebarPerfProbeTogglesTab.tsx similarity index 95% rename from src/components/sidebar/perfProbe/SidebarPerfProbeTogglesTab.tsx rename to src/features/sidebar/components/perfProbe/SidebarPerfProbeTogglesTab.tsx index c998180e..9f3357b4 100644 --- a/src/components/sidebar/perfProbe/SidebarPerfProbeTogglesTab.tsx +++ b/src/features/sidebar/components/perfProbe/SidebarPerfProbeTogglesTab.tsx @@ -1,12 +1,12 @@ import { useState, type CSSProperties } from 'react'; import { ChevronRight } from 'lucide-react'; -import { setPerfProbeFlag, type PerfProbeFlags } from '../../../utils/perf/perfFlags'; -import type { PerfToggleEngineLeaf, PerfToggleLeaf, PerfToggleNode } from '../../../utils/perf/perfProbeToggleTree'; +import { setPerfProbeFlag, type PerfProbeFlags } from '@/utils/perf/perfFlags'; +import type { PerfToggleEngineLeaf, PerfToggleLeaf, PerfToggleNode } from '@/utils/perf/perfProbeToggleTree'; import { isPerfToggleEngineLeaf, isPerfToggleGroup, PERF_PROBE_TOGGLE_TREE, -} from '../../../utils/perf/perfProbeToggleTree'; +} from '@/utils/perf/perfProbeToggleTree'; interface EngineProps { hotCacheEnabled: boolean; diff --git a/src/components/sidebar/perfProbe/SidebarPerfProbeTuningTab.tsx b/src/features/sidebar/components/perfProbe/SidebarPerfProbeTuningTab.tsx similarity index 76% rename from src/components/sidebar/perfProbe/SidebarPerfProbeTuningTab.tsx rename to src/features/sidebar/components/perfProbe/SidebarPerfProbeTuningTab.tsx index df4be0d4..b2b7230e 100644 --- a/src/components/sidebar/perfProbe/SidebarPerfProbeTuningTab.tsx +++ b/src/features/sidebar/components/perfProbe/SidebarPerfProbeTuningTab.tsx @@ -1,4 +1,4 @@ -import PerfCoverThreadsControl from './PerfCoverThreadsControl'; +import PerfCoverThreadsControl from '@/features/sidebar/components/perfProbe/PerfCoverThreadsControl'; export default function SidebarPerfProbeTuningTab() { return ( diff --git a/src/hooks/useSidebarLibraryDropdown.ts b/src/features/sidebar/hooks/useSidebarLibraryDropdown.ts similarity index 100% rename from src/hooks/useSidebarLibraryDropdown.ts rename to src/features/sidebar/hooks/useSidebarLibraryDropdown.ts diff --git a/src/hooks/useSidebarNavDnd.ts b/src/features/sidebar/hooks/useSidebarNavDnd.ts similarity index 97% rename from src/hooks/useSidebarNavDnd.ts rename to src/features/sidebar/hooks/useSidebarNavDnd.ts index 7890f19b..bfe7829f 100644 --- a/src/hooks/useSidebarNavDnd.ts +++ b/src/features/sidebar/hooks/useSidebarNavDnd.ts @@ -1,15 +1,15 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; -import type { SidebarItemConfig } from '../store/sidebarStore'; +import type { SidebarItemConfig } from '@/features/sidebar/store/sidebarStore'; import { applySidebarReorderById, isSidebarNavItemUserHideable, type SidebarNavDropTarget, -} from '../utils/componentHelpers/sidebarNavReorder'; +} from '@/features/sidebar/utils/sidebarNavReorder'; import { SIDEBAR_NAV_LONG_PRESS_MOVE_CANCEL_PX, SIDEBAR_NAV_LONG_PRESS_MS, isPointerOutsideAsideSidebar, -} from '../utils/componentHelpers/sidebarHelpers'; +} from '@/features/sidebar/utils/sidebarHelpers'; interface NavDndState { section: 'library' | 'system'; diff --git a/src/hooks/useSidebarNewReleasesUnread.ts b/src/features/sidebar/hooks/useSidebarNewReleasesUnread.ts similarity index 97% rename from src/hooks/useSidebarNewReleasesUnread.ts rename to src/features/sidebar/hooks/useSidebarNewReleasesUnread.ts index fd1f296b..3467ae67 100644 --- a/src/hooks/useSidebarNewReleasesUnread.ts +++ b/src/features/sidebar/hooks/useSidebarNewReleasesUnread.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { getAlbumList } from '../api/subsonicLibrary'; -import { isActiveServerReachable } from '../utils/network/activeServerReachability'; +import { getAlbumList } from '@/api/subsonicLibrary'; +import { isActiveServerReachable } from '@/utils/network/activeServerReachability'; import { NEW_RELEASES_RESET_DELAY_MS, NEW_RELEASES_SEEN_MAX_IDS, @@ -8,7 +8,7 @@ import { NEW_RELEASES_UNREAD_SAMPLE_SIZE, NEW_RELEASES_UNREAD_STORAGE_PREFIX, mergeSeenNewReleaseIdsCap, -} from '../utils/componentHelpers/sidebarHelpers'; +} from '@/features/sidebar/utils/sidebarHelpers'; interface Args { serverId: string; diff --git a/src/hooks/useSidebarPerfProbe.ts b/src/features/sidebar/hooks/useSidebarPerfProbe.ts similarity index 89% rename from src/hooks/useSidebarPerfProbe.ts rename to src/features/sidebar/hooks/useSidebarPerfProbe.ts index 8fcedfff..bc078a61 100644 --- a/src/hooks/useSidebarPerfProbe.ts +++ b/src/features/sidebar/hooks/useSidebarPerfProbe.ts @@ -1,14 +1,14 @@ import { useEffect, useState } from 'react'; -import { acquirePerfLivePoll, patchPerfLiveAnalysis } from '../utils/perf/perfLiveStore'; -import { setPerfProbeTelemetryActive } from '../utils/perf/perfTelemetry'; -import { useAnalysisPerfLast } from '../utils/perf/analysisPerfStore'; -import { useAnalysisPerfListener } from './useAnalysisPerfListener'; -import { useCoverPerfListener, useCoverUiThroughputPoll } from './useCoverPerfListener'; +import { acquirePerfLivePoll, patchPerfLiveAnalysis } from '@/utils/perf/perfLiveStore'; +import { setPerfProbeTelemetryActive } from '@/utils/perf/perfTelemetry'; +import { useAnalysisPerfLast } from '@/utils/perf/analysisPerfStore'; +import { useAnalysisPerfListener } from '@/hooks/useAnalysisPerfListener'; +import { useCoverPerfListener, useCoverUiThroughputPoll } from '@/hooks/useCoverPerfListener'; import { getPerfProbeFlags, subscribePerfProbeFlags, -} from '../utils/perf/perfFlags'; -import { hasAnyLiveMetricPollNeed, usePerfLiveOverlayPins } from '../utils/perf/perfOverlayPins'; +} from '@/utils/perf/perfFlags'; +import { hasAnyLiveMetricPollNeed, usePerfLiveOverlayPins } from '@/utils/perf/perfOverlayPins'; import { useSyncExternalStore } from 'react'; interface Result { diff --git a/src/hooks/useSidebarScrollVisible.ts b/src/features/sidebar/hooks/useSidebarScrollVisible.ts similarity index 100% rename from src/hooks/useSidebarScrollVisible.ts rename to src/features/sidebar/hooks/useSidebarScrollVisible.ts diff --git a/src/features/sidebar/index.ts b/src/features/sidebar/index.ts new file mode 100644 index 00000000..85a48f3d --- /dev/null +++ b/src/features/sidebar/index.ts @@ -0,0 +1,9 @@ +/** + * Sidebar feature — the primary nav sidebar (library/system nav, playlists + * section, library picker, active jobs) plus its nav config store, reorder + * helpers, and the in-sidebar performance-probe overlay (Ctrl+Shift+P). + */ +export { default } from './components/Sidebar'; +export { useSidebarStore, CONSERVED_SIDEBAR_NAV_IDS } from './store/sidebarStore'; +export type { SidebarItemConfig } from './store/sidebarStore'; +export { applySidebarReorderById, resolveStartRoute } from './utils/sidebarNavReorder'; diff --git a/src/store/sidebarStore.ts b/src/features/sidebar/store/sidebarStore.ts similarity index 100% rename from src/store/sidebarStore.ts rename to src/features/sidebar/store/sidebarStore.ts diff --git a/src/utils/componentHelpers/sidebarHelpers.ts b/src/features/sidebar/utils/sidebarHelpers.ts similarity index 100% rename from src/utils/componentHelpers/sidebarHelpers.ts rename to src/features/sidebar/utils/sidebarHelpers.ts diff --git a/src/utils/componentHelpers/sidebarNavReorder.test.ts b/src/features/sidebar/utils/sidebarNavReorder.test.ts similarity index 96% rename from src/utils/componentHelpers/sidebarNavReorder.test.ts rename to src/features/sidebar/utils/sidebarNavReorder.test.ts index c1ff99f5..f3478c72 100644 --- a/src/utils/componentHelpers/sidebarNavReorder.test.ts +++ b/src/features/sidebar/utils/sidebarNavReorder.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { applySidebarReorderById, resolveStartRoute } from './sidebarNavReorder'; -import { DEFAULT_SIDEBAR_ITEMS, type SidebarItemConfig } from '../../store/sidebarStore'; +import { applySidebarReorderById, resolveStartRoute } from '@/features/sidebar/utils/sidebarNavReorder'; +import { DEFAULT_SIDEBAR_ITEMS, type SidebarItemConfig } from '@/features/sidebar/store/sidebarStore'; const hide = (items: SidebarItemConfig[], ...ids: string[]): SidebarItemConfig[] => items.map(i => (ids.includes(i.id) ? { ...i, visible: false } : i)); diff --git a/src/utils/componentHelpers/sidebarNavReorder.ts b/src/features/sidebar/utils/sidebarNavReorder.ts similarity index 96% rename from src/utils/componentHelpers/sidebarNavReorder.ts rename to src/features/sidebar/utils/sidebarNavReorder.ts index c052d55e..c0041fc9 100644 --- a/src/utils/componentHelpers/sidebarNavReorder.ts +++ b/src/features/sidebar/utils/sidebarNavReorder.ts @@ -1,6 +1,6 @@ -import { ALL_NAV_ITEMS } from '../../config/navItems'; -import { CONSERVED_SIDEBAR_NAV_IDS, type SidebarItemConfig } from '../../store/sidebarStore'; -import { applyListReorderById, type ListReorderDropTarget } from './listReorder'; +import { ALL_NAV_ITEMS } from '@/config/navItems'; +import { CONSERVED_SIDEBAR_NAV_IDS, type SidebarItemConfig } from '@/features/sidebar/store/sidebarStore'; +import { applyListReorderById, type ListReorderDropTarget } from '@/utils/componentHelpers/listReorder'; export type SidebarNavSection = 'library' | 'system';