refactor(sidebar): co-locate sidebar feature into features/sidebar

This commit is contained in:
Psychotoxical
2026-06-29 23:26:00 +02:00
parent e6269c7b85
commit e0e10e0034
34 changed files with 117 additions and 108 deletions
+2 -2
View File
@@ -2,10 +2,10 @@ import { lazy } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom'; import { Navigate, Route, Routes } from 'react-router-dom';
import MobilePlayerView from '../components/MobilePlayerView'; import MobilePlayerView from '../components/MobilePlayerView';
import { useIsMobile } from '../hooks/useIsMobile'; import { useIsMobile } from '../hooks/useIsMobile';
import { useSidebarStore } from '../store/sidebarStore'; import { useSidebarStore } from '@/features/sidebar';
import { useAuthStore } from '../store/authStore'; import { useAuthStore } from '../store/authStore';
import { useLuckyMixAvailable } from '../hooks/useLuckyMixAvailable'; 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 // 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. // the entry chunk; each page is fetched when its route is first visited.
+1 -1
View File
@@ -5,7 +5,7 @@ import { navigatePathWithAlbumReturnTo, shouldSkipMainScrollResetOnRouteChange }
import { getCurrentWebview } from '@tauri-apps/api/webview'; import { getCurrentWebview } from '@tauri-apps/api/webview';
import { PanelRight } from 'lucide-react'; import { PanelRight } from 'lucide-react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Sidebar from '../components/Sidebar'; import Sidebar from '@/features/sidebar';
import PlayerBar from '../components/PlayerBar'; import PlayerBar from '../components/PlayerBar';
import BottomNav from '../components/BottomNav'; import BottomNav from '../components/BottomNav';
import { useIsMobile } from '../hooks/useIsMobile'; import { useIsMobile } from '../hooks/useIsMobile';
+1 -1
View File
@@ -2,7 +2,7 @@ import { createPortal } from 'react-dom';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Settings, HardDriveDownload } from 'lucide-react'; import { Settings, HardDriveDownload } from 'lucide-react';
import { useSidebarStore } from '../store/sidebarStore'; import { useSidebarStore } from '@/features/sidebar';
import { useAuthStore } from '../store/authStore'; import { useAuthStore } from '../store/authStore';
import { ALL_NAV_ITEMS } from '../config/navItems'; import { ALL_NAV_ITEMS } from '../config/navItems';
import { useLuckyMixAvailable } from '../hooks/useLuckyMixAvailable'; import { useLuckyMixAvailable } from '../hooks/useLuckyMixAvailable';
@@ -7,7 +7,7 @@ import { useHomeStore } from '../../store/homeStore';
import { usePlayerBarLayoutStore } from '../../store/playerBarLayoutStore'; import { usePlayerBarLayoutStore } from '../../store/playerBarLayoutStore';
import { usePlaylistLayoutStore } from '../../store/playlistLayoutStore'; import { usePlaylistLayoutStore } from '../../store/playlistLayoutStore';
import { useQueueToolbarStore } from '../../store/queueToolbarStore'; import { useQueueToolbarStore } from '../../store/queueToolbarStore';
import { useSidebarStore } from '../../store/sidebarStore'; import { useSidebarStore } from '@/features/sidebar';
import SettingsSubSection from '../SettingsSubSection'; import SettingsSubSection from '../SettingsSubSection';
import { SettingsGroup } from './SettingsGroup'; import { SettingsGroup } from './SettingsGroup';
import { SettingsToggle } from './SettingsToggle'; import { SettingsToggle } from './SettingsToggle';
@@ -1,10 +1,10 @@
import { useCallback, useRef } from 'react'; import { useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useAuthStore } from '../../store/authStore'; 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 { useLuckyMixAvailable } from '../../hooks/useLuckyMixAvailable';
import { ALL_NAV_ITEMS } from '../../config/navItems'; import { ALL_NAV_ITEMS } from '../../config/navItems';
import { applySidebarReorderById } from '../../utils/componentHelpers/sidebarNavReorder'; import { applySidebarReorderById } from '@/features/sidebar';
import { useListReorderDnd } from '../../hooks/useListReorderDnd'; import { useListReorderDnd } from '../../hooks/useListReorderDnd';
import type { ListReorderDropTarget } from '../../utils/componentHelpers/listReorder'; import type { ListReorderDropTarget } from '../../utils/componentHelpers/listReorder';
import { ReorderGripHandle } from './ReorderGripHandle'; import { ReorderGripHandle } from './ReorderGripHandle';
@@ -1,34 +1,34 @@
import { useState, useRef, useEffect, useMemo } from 'react'; import { useState, useRef, useEffect, useMemo } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { usePlayerStore } from '../store/playerStore'; import { usePlayerStore } from '@/store/playerStore';
import { useOfflineJobStore } from '../store/offlineJobStore'; import { useOfflineJobStore } from '@/store/offlineJobStore';
import { clearOfflinePinTasks } from '../utils/offline/offlinePinQueue'; import { clearOfflinePinTasks } from '@/utils/offline/offlinePinQueue';
import { useDeviceSyncJobStore } from '@/features/deviceSync'; import { useDeviceSyncJobStore } from '@/features/deviceSync';
import { useAuthStore } from '../store/authStore'; import { useAuthStore } from '@/store/authStore';
import { useSidebarStore } from '../store/sidebarStore'; import { useSidebarStore } from '@/features/sidebar/store/sidebarStore';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PanelLeft, PanelLeftClose, Trash2 } from 'lucide-react'; import { PanelLeft, PanelLeftClose, Trash2 } from 'lucide-react';
import PsysonicLogo from './PsysonicLogo'; import PsysonicLogo from '@/components/PsysonicLogo';
import PSmallLogo from './PSmallLogo'; import PSmallLogo from '@/components/PSmallLogo';
import { usePlaylistStore } from '../store/playlistStore'; import { usePlaylistStore } from '@/store/playlistStore';
import OverlayScrollArea from '@/ui/OverlayScrollArea'; import OverlayScrollArea from '@/ui/OverlayScrollArea';
import { import {
getLibraryItemsForReorder, getLibraryItemsForReorder,
getSystemItemsForReorder, getSystemItemsForReorder,
} from '../utils/componentHelpers/sidebarNavReorder'; } from '@/features/sidebar/utils/sidebarNavReorder';
import { useLuckyMixAvailable } from '../hooks/useLuckyMixAvailable'; import { useLuckyMixAvailable } from '@/hooks/useLuckyMixAvailable';
import { usePerfProbeFlags } from '../utils/perf/perfFlags'; import { usePerfProbeFlags } from '@/utils/perf/perfFlags';
import { useSidebarNewReleasesUnread } from '../hooks/useSidebarNewReleasesUnread'; import { useSidebarNewReleasesUnread } from '@/features/sidebar/hooks/useSidebarNewReleasesUnread';
import { useSidebarNavDnd } from '../hooks/useSidebarNavDnd'; import { useSidebarNavDnd } from '@/features/sidebar/hooks/useSidebarNavDnd';
import { useSidebarLibraryDropdown } from '../hooks/useSidebarLibraryDropdown'; import { useSidebarLibraryDropdown } from '@/features/sidebar/hooks/useSidebarLibraryDropdown';
import { useSidebarScrollVisible } from '../hooks/useSidebarScrollVisible'; import { useSidebarScrollVisible } from '@/features/sidebar/hooks/useSidebarScrollVisible';
import { isOfflineSidebarNavAllowed } from '../utils/offline/offlineNavPolicy'; import { isOfflineSidebarNavAllowed } from '@/utils/offline/offlineNavPolicy';
import { useOfflineBrowseContext } from '../hooks/useOfflineBrowseContext'; import { useOfflineBrowseContext } from '@/hooks/useOfflineBrowseContext';
import { offlineBrowseNavFlags } from '../utils/offline/offlineBrowseContext'; import { offlineBrowseNavFlags } from '@/utils/offline/offlineBrowseContext';
import { useSidebarPerfProbe } from '../hooks/useSidebarPerfProbe'; import { useSidebarPerfProbe } from '@/features/sidebar/hooks/useSidebarPerfProbe';
import SidebarPerfProbeModal from './sidebar/SidebarPerfProbeModal'; import SidebarPerfProbeModal from '@/features/sidebar/components/SidebarPerfProbeModal';
import SidebarNavBody from './sidebar/SidebarNavBody'; import SidebarNavBody from '@/features/sidebar/components/SidebarNavBody';
export default function Sidebar({ export default function Sidebar({
@@ -2,13 +2,13 @@ import React from 'react';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { AudioLines, ChevronRight, HardDriveDownload, Settings } from 'lucide-react'; import { AudioLines, ChevronRight, HardDriveDownload, Settings } from 'lucide-react';
import type { SidebarItemConfig } from '../../store/sidebarStore'; import type { SidebarItemConfig } from '@/features/sidebar/store/sidebarStore';
import { ALL_NAV_ITEMS } from '../../config/navItems'; import { ALL_NAV_ITEMS } from '@/config/navItems';
import WhatsNewBanner from '../WhatsNewBanner'; import WhatsNewBanner from '@/components/WhatsNewBanner';
import ThemeUpdateBanner from '../ThemeUpdateBanner'; import ThemeUpdateBanner from '@/components/ThemeUpdateBanner';
import SidebarLibraryPicker from './SidebarLibraryPicker'; import SidebarLibraryPicker from '@/features/sidebar/components/SidebarLibraryPicker';
import SidebarPlaylistsSection from './SidebarPlaylistsSection'; import SidebarPlaylistsSection from '@/features/sidebar/components/SidebarPlaylistsSection';
import SidebarActiveJobs from './SidebarActiveJobs'; import SidebarActiveJobs from '@/features/sidebar/components/SidebarActiveJobs';
interface NavDndState { interface NavDndState {
section: 'library' | 'system'; section: 'library' | 'system';
@@ -1,15 +1,15 @@
import { useState } from 'react'; import { useState } from 'react';
import { Activity, Network, ScrollText, SlidersHorizontal, Wrench, X } from 'lucide-react'; import { Activity, Network, ScrollText, SlidersHorizontal, Wrench, X } from 'lucide-react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import SidebarPerfProbeMonitorTab from './perfProbe/SidebarPerfProbeMonitorTab'; import SidebarPerfProbeMonitorTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeMonitorTab';
import SidebarPerfProbeTogglesTab from './perfProbe/SidebarPerfProbeTogglesTab'; import SidebarPerfProbeTogglesTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeTogglesTab';
import SidebarPerfProbeTuningTab from './perfProbe/SidebarPerfProbeTuningTab'; import SidebarPerfProbeTuningTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeTuningTab';
import SidebarPerfProbeLogsTab from './perfProbe/SidebarPerfProbeLogsTab'; import SidebarPerfProbeLogsTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeLogsTab';
import SidebarPerfProbeConnectionsTab from './perfProbe/SidebarPerfProbeConnectionsTab'; import SidebarPerfProbeConnectionsTab from '@/features/sidebar/components/perfProbe/SidebarPerfProbeConnectionsTab';
import { resetPerfProbeFlags, type PerfProbeFlags } from '../../utils/perf/perfFlags'; import { resetPerfProbeFlags, type PerfProbeFlags } from '@/utils/perf/perfFlags';
import { clearPerfLiveOverlayPins } from '../../utils/perf/perfOverlayPins'; import { clearPerfLiveOverlayPins } from '@/utils/perf/perfOverlayPins';
import { resetPerfOverlayAppearance } from '../../utils/perf/perfOverlayAppearance'; import { resetPerfOverlayAppearance } from '@/utils/perf/perfOverlayAppearance';
import { resetPerfOverlayMode } from '../../utils/perf/perfOverlayMode'; import { resetPerfOverlayMode } from '@/utils/perf/perfOverlayMode';
type TabId = 'monitor' | 'connections' | 'toggles' | 'tuning' | 'logs'; type TabId = 'monitor' | 'connections' | 'toggles' | 'tuning' | 'logs';
@@ -2,12 +2,12 @@ import React from 'react';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { ChevronRight, Folder, PlayCircle, Sparkles } from 'lucide-react'; import { ChevronRight, Folder, PlayCircle, Sparkles } from 'lucide-react';
import { displayPlaylistName, isSmartPlaylistName } from '../../utils/componentHelpers/sidebarHelpers'; import { displayPlaylistName, isSmartPlaylistName } from '@/features/sidebar/utils/sidebarHelpers';
import { useAuthStore } from '../../store/authStore'; import { useAuthStore } from '@/store/authStore';
import { usePlayerStore } from '../../store/playerStore'; import { usePlayerStore } from '@/store/playerStore';
import { usePlaylistStore } from '../../store/playlistStore'; import { usePlaylistStore } from '@/store/playlistStore';
import { EMPTY_SERVER_FOLDERS, usePlaylistFolderStore } from '../../store/playlistFolderStore'; import { EMPTY_SERVER_FOLDERS, usePlaylistFolderStore } from '@/store/playlistFolderStore';
import { groupPlaylistsByFolder } from '../../utils/playlist/playlistFolders'; import { groupPlaylistsByFolder } from '@/utils/playlist/playlistFolders';
interface SidebarPlaylist { interface SidebarPlaylist {
id: string; id: string;
@@ -4,7 +4,7 @@ import {
libraryCoverBackfillResetCursor, libraryCoverBackfillResetCursor,
libraryCoverBackfillRunFullPass, libraryCoverBackfillRunFullPass,
libraryCoverBackfillSetParallel, libraryCoverBackfillSetParallel,
} from '../../../api/coverCache'; } from '@/api/coverCache';
const COVER_THREADS_MIN = 1; const COVER_THREADS_MIN = 1;
const COVER_THREADS_MAX = 16; const COVER_THREADS_MAX = 16;
@@ -1,4 +1,4 @@
import { perfLiveCpuSnapshotSupported } from '../../../utils/perf/perfLiveCpuSnapshot'; import { perfLiveCpuSnapshotSupported } from '@/utils/perf/perfLiveCpuSnapshot';
import { import {
PERF_LIVE_POLL_MS_MAX, PERF_LIVE_POLL_MS_MAX,
PERF_LIVE_POLL_MS_MIN, PERF_LIVE_POLL_MS_MIN,
@@ -7,7 +7,7 @@ import {
setPerfLivePollIntervalMs, setPerfLivePollIntervalMs,
usePerfLiveIncludeThreadGroups, usePerfLiveIncludeThreadGroups,
usePerfLivePollIntervalMs, usePerfLivePollIntervalMs,
} from '../../../utils/perf/perfLivePollSettings'; } from '@/utils/perf/perfLivePollSettings';
export default function PerfLivePollControls() { export default function PerfLivePollControls() {
const pollMs = usePerfLivePollIntervalMs(); const pollMs = usePerfLivePollIntervalMs();
@@ -3,7 +3,7 @@ import {
setPerfOverlayCorner, setPerfOverlayCorner,
setPerfOverlayOpacity, setPerfOverlayOpacity,
usePerfOverlayAppearance, usePerfOverlayAppearance,
} from '../../../utils/perf/perfOverlayAppearance'; } from '@/utils/perf/perfOverlayAppearance';
export default function PerfOverlayAppearanceControls() { export default function PerfOverlayAppearanceControls() {
const { corner, opacity } = usePerfOverlayAppearance(); const { corner, opacity } = usePerfOverlayAppearance();
@@ -2,7 +2,7 @@ import {
PERF_OVERLAY_MODE_OPTIONS, PERF_OVERLAY_MODE_OPTIONS,
setPerfOverlayMode, setPerfOverlayMode,
usePerfOverlayMode, usePerfOverlayMode,
} from '../../../utils/perf/perfOverlayMode'; } from '@/utils/perf/perfOverlayMode';
export default function PerfOverlayModeControls() { export default function PerfOverlayModeControls() {
const mode = usePerfOverlayMode(); const mode = usePerfOverlayMode();
@@ -1,13 +1,13 @@
import { useAuthStore } from '../../../store/authStore'; import { useAuthStore } from '@/store/authStore';
import { usePlayerStore } from '../../../store/playerStore'; import { usePlayerStore } from '@/store/playerStore';
import { useConnectionStatus } from '../../../hooks/useConnectionStatus'; import { useConnectionStatus } from '@/hooks/useConnectionStatus';
import { useNavidromeAdminRole } from '../../../hooks/useNavidromeAdminRole'; import { useNavidromeAdminRole } from '@/hooks/useNavidromeAdminRole';
import { serverListDisplayLabel } from '../../../utils/server/serverDisplayName'; import { serverListDisplayLabel } from '@/utils/server/serverDisplayName';
import { findServerByIdOrIndexKey } from '../../../utils/server/serverLookup'; import { findServerByIdOrIndexKey } from '@/utils/server/serverLookup';
import { PerfProbeMetricSection } from './PerfProbeMetricCard'; import { PerfProbeMetricSection } from '@/features/sidebar/components/perfProbe/PerfProbeMetricCard';
import PerfProbeDetailList from './PerfProbeDetailList'; import PerfProbeDetailList from '@/features/sidebar/components/perfProbe/PerfProbeDetailList';
import PerfProbeStatusBadge, { type PerfProbeBadgeTone } from './PerfProbeStatusBadge'; import PerfProbeStatusBadge, { type PerfProbeBadgeTone } from '@/features/sidebar/components/perfProbe/PerfProbeStatusBadge';
import SidebarPerfProbeServerSection from './SidebarPerfProbeServerSection'; import SidebarPerfProbeServerSection from '@/features/sidebar/components/perfProbe/SidebarPerfProbeServerSection';
function connectionStatusBadge(status: string): { tone: PerfProbeBadgeTone; label: string } { function connectionStatusBadge(status: string): { tone: PerfProbeBadgeTone; label: string } {
switch (status) { switch (status) {
@@ -11,13 +11,13 @@ import { Copy, Download, Pause, Play, Trash2 } from 'lucide-react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { save as saveDialog } from '@tauri-apps/plugin-dialog'; import { save as saveDialog } from '@tauri-apps/plugin-dialog';
import { writeFile } from '@tauri-apps/plugin-fs'; 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 { invoke } from '@tauri-apps/api/core';
import { useAuthStore } from '../../../store/authStore'; import { useAuthStore } from '@/store/authStore';
import type { LoggingMode } from '../../../store/authStoreTypes'; import type { LoggingMode } from '@/store/authStoreTypes';
import CustomSelect from '@/ui/CustomSelect'; import CustomSelect from '@/ui/CustomSelect';
import { filterLogLines } from '../../../utils/perf/filterLogLines'; import { filterLogLines } from '@/utils/perf/filterLogLines';
import { sanitizeLogLine } from '../../../utils/perf/sanitizeLogLine'; import { sanitizeLogLine } from '@/utils/perf/sanitizeLogLine';
function formatLogLinesText(lines: RuntimeLogLine[]): string { function formatLogLinesText(lines: RuntimeLogLine[]): string {
return lines.map(line => line.text).join('\n'); return lines.map(line => line.text).join('\n');
@@ -1,17 +1,17 @@
import { useMemo, useRef } from 'react'; import { useMemo, useRef } from 'react';
import { isPerfLivePollWaitingForCpu, usePerfLiveSnapshot } from '../../../utils/perf/perfLiveStore'; import { isPerfLivePollWaitingForCpu, usePerfLiveSnapshot } from '@/utils/perf/perfLiveStore';
import { usePerfLiveIncludeThreadGroups } from '../../../utils/perf/perfLivePollSettings'; import { usePerfLiveIncludeThreadGroups } from '@/utils/perf/perfLivePollSettings';
import { import {
togglePerfLiveOverlayPin, togglePerfLiveOverlayPin,
togglePipelineOverlayPin, togglePipelineOverlayPin,
usePerfLiveOverlayPins, usePerfLiveOverlayPins,
usePipelineOverlayPinned, usePipelineOverlayPinned,
type PerfLiveOverlayPinId, type PerfLiveOverlayPinId,
} from '../../../utils/perf/perfOverlayPins'; } from '@/utils/perf/perfOverlayPins';
import PerfProbeMetricCard, { PerfProbeMetricSection } from './PerfProbeMetricCard'; import PerfProbeMetricCard, { PerfProbeMetricSection } from '@/features/sidebar/components/perfProbe/PerfProbeMetricCard';
import PerfOverlayAppearanceControls from './PerfOverlayAppearanceControls'; import PerfOverlayAppearanceControls from '@/features/sidebar/components/perfProbe/PerfOverlayAppearanceControls';
import PerfOverlayModeControls from './PerfOverlayModeControls'; import PerfOverlayModeControls from '@/features/sidebar/components/perfProbe/PerfOverlayModeControls';
import PerfLivePollControls from './PerfLivePollControls'; import PerfLivePollControls from '@/features/sidebar/components/perfProbe/PerfLivePollControls';
function memoryBarPct(rssKb: number, maxKb: number): number { function memoryBarPct(rssKb: number, maxKb: number): number {
if (maxKb <= 0) return 0; if (maxKb <= 0) return 0;
@@ -1,16 +1,16 @@
import { useAuthStore } from '../../../store/authStore'; import { useAuthStore } from '@/store/authStore';
import type { NavidromeAdminRole } from '../../../hooks/useNavidromeAdminRole'; import type { NavidromeAdminRole } from '@/hooks/useNavidromeAdminRole';
import { isNavidromeServer, formatServerSoftware } from '../../../utils/server/subsonicServerIdentity'; import { isNavidromeServer, formatServerSoftware } from '@/utils/server/subsonicServerIdentity';
import { FEATURE_AUDIOMUSE_SIMILAR_TRACKS, OP_SIMILAR_TRACKS } from '../../../serverCapabilities/catalog'; import { FEATURE_AUDIOMUSE_SIMILAR_TRACKS, OP_SIMILAR_TRACKS } from '@/serverCapabilities/catalog';
import { import {
isFeatureActiveForServer, isFeatureActiveForServer,
resolveCallRoutesForServer, resolveCallRoutesForServer,
resolveFeatureForServer, resolveFeatureForServer,
} from '../../../serverCapabilities/storeView'; } from '@/serverCapabilities/storeView';
import type { CapabilityStatus, FeatureTrust, ResolvedCapability } from '../../../serverCapabilities/types'; import type { CapabilityStatus, FeatureTrust, ResolvedCapability } from '@/serverCapabilities/types';
import { PerfProbeMetricSection } from './PerfProbeMetricCard'; import { PerfProbeMetricSection } from '@/features/sidebar/components/perfProbe/PerfProbeMetricCard';
import PerfProbeDetailList, { type PerfProbeDetailRow } from './PerfProbeDetailList'; import PerfProbeDetailList, { type PerfProbeDetailRow } from '@/features/sidebar/components/perfProbe/PerfProbeDetailList';
import PerfProbeStatusBadge, { type PerfProbeBadgeTone } from './PerfProbeStatusBadge'; import PerfProbeStatusBadge, { type PerfProbeBadgeTone } from '@/features/sidebar/components/perfProbe/PerfProbeStatusBadge';
function detectionBadge(status: CapabilityStatus): { tone: PerfProbeBadgeTone; label: string } { function detectionBadge(status: CapabilityStatus): { tone: PerfProbeBadgeTone; label: string } {
switch (status) { switch (status) {
@@ -1,12 +1,12 @@
import { useState, type CSSProperties } from 'react'; import { useState, type CSSProperties } from 'react';
import { ChevronRight } from 'lucide-react'; import { ChevronRight } from 'lucide-react';
import { setPerfProbeFlag, type PerfProbeFlags } from '../../../utils/perf/perfFlags'; import { setPerfProbeFlag, type PerfProbeFlags } from '@/utils/perf/perfFlags';
import type { PerfToggleEngineLeaf, PerfToggleLeaf, PerfToggleNode } from '../../../utils/perf/perfProbeToggleTree'; import type { PerfToggleEngineLeaf, PerfToggleLeaf, PerfToggleNode } from '@/utils/perf/perfProbeToggleTree';
import { import {
isPerfToggleEngineLeaf, isPerfToggleEngineLeaf,
isPerfToggleGroup, isPerfToggleGroup,
PERF_PROBE_TOGGLE_TREE, PERF_PROBE_TOGGLE_TREE,
} from '../../../utils/perf/perfProbeToggleTree'; } from '@/utils/perf/perfProbeToggleTree';
interface EngineProps { interface EngineProps {
hotCacheEnabled: boolean; hotCacheEnabled: boolean;
@@ -1,4 +1,4 @@
import PerfCoverThreadsControl from './PerfCoverThreadsControl'; import PerfCoverThreadsControl from '@/features/sidebar/components/perfProbe/PerfCoverThreadsControl';
export default function SidebarPerfProbeTuningTab() { export default function SidebarPerfProbeTuningTab() {
return ( return (
@@ -1,15 +1,15 @@
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import type { SidebarItemConfig } from '../store/sidebarStore'; import type { SidebarItemConfig } from '@/features/sidebar/store/sidebarStore';
import { import {
applySidebarReorderById, applySidebarReorderById,
isSidebarNavItemUserHideable, isSidebarNavItemUserHideable,
type SidebarNavDropTarget, type SidebarNavDropTarget,
} from '../utils/componentHelpers/sidebarNavReorder'; } from '@/features/sidebar/utils/sidebarNavReorder';
import { import {
SIDEBAR_NAV_LONG_PRESS_MOVE_CANCEL_PX, SIDEBAR_NAV_LONG_PRESS_MOVE_CANCEL_PX,
SIDEBAR_NAV_LONG_PRESS_MS, SIDEBAR_NAV_LONG_PRESS_MS,
isPointerOutsideAsideSidebar, isPointerOutsideAsideSidebar,
} from '../utils/componentHelpers/sidebarHelpers'; } from '@/features/sidebar/utils/sidebarHelpers';
interface NavDndState { interface NavDndState {
section: 'library' | 'system'; section: 'library' | 'system';
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { getAlbumList } from '../api/subsonicLibrary'; import { getAlbumList } from '@/api/subsonicLibrary';
import { isActiveServerReachable } from '../utils/network/activeServerReachability'; import { isActiveServerReachable } from '@/utils/network/activeServerReachability';
import { import {
NEW_RELEASES_RESET_DELAY_MS, NEW_RELEASES_RESET_DELAY_MS,
NEW_RELEASES_SEEN_MAX_IDS, NEW_RELEASES_SEEN_MAX_IDS,
@@ -8,7 +8,7 @@ import {
NEW_RELEASES_UNREAD_SAMPLE_SIZE, NEW_RELEASES_UNREAD_SAMPLE_SIZE,
NEW_RELEASES_UNREAD_STORAGE_PREFIX, NEW_RELEASES_UNREAD_STORAGE_PREFIX,
mergeSeenNewReleaseIdsCap, mergeSeenNewReleaseIdsCap,
} from '../utils/componentHelpers/sidebarHelpers'; } from '@/features/sidebar/utils/sidebarHelpers';
interface Args { interface Args {
serverId: string; serverId: string;
@@ -1,14 +1,14 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { acquirePerfLivePoll, patchPerfLiveAnalysis } from '../utils/perf/perfLiveStore'; import { acquirePerfLivePoll, patchPerfLiveAnalysis } from '@/utils/perf/perfLiveStore';
import { setPerfProbeTelemetryActive } from '../utils/perf/perfTelemetry'; import { setPerfProbeTelemetryActive } from '@/utils/perf/perfTelemetry';
import { useAnalysisPerfLast } from '../utils/perf/analysisPerfStore'; import { useAnalysisPerfLast } from '@/utils/perf/analysisPerfStore';
import { useAnalysisPerfListener } from './useAnalysisPerfListener'; import { useAnalysisPerfListener } from '@/hooks/useAnalysisPerfListener';
import { useCoverPerfListener, useCoverUiThroughputPoll } from './useCoverPerfListener'; import { useCoverPerfListener, useCoverUiThroughputPoll } from '@/hooks/useCoverPerfListener';
import { import {
getPerfProbeFlags, getPerfProbeFlags,
subscribePerfProbeFlags, subscribePerfProbeFlags,
} from '../utils/perf/perfFlags'; } from '@/utils/perf/perfFlags';
import { hasAnyLiveMetricPollNeed, usePerfLiveOverlayPins } from '../utils/perf/perfOverlayPins'; import { hasAnyLiveMetricPollNeed, usePerfLiveOverlayPins } from '@/utils/perf/perfOverlayPins';
import { useSyncExternalStore } from 'react'; import { useSyncExternalStore } from 'react';
interface Result { interface Result {
+9
View File
@@ -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';
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
import { applySidebarReorderById, resolveStartRoute } from './sidebarNavReorder'; import { applySidebarReorderById, resolveStartRoute } from '@/features/sidebar/utils/sidebarNavReorder';
import { DEFAULT_SIDEBAR_ITEMS, type SidebarItemConfig } from '../../store/sidebarStore'; import { DEFAULT_SIDEBAR_ITEMS, type SidebarItemConfig } from '@/features/sidebar/store/sidebarStore';
const hide = (items: SidebarItemConfig[], ...ids: string[]): SidebarItemConfig[] => const hide = (items: SidebarItemConfig[], ...ids: string[]): SidebarItemConfig[] =>
items.map(i => (ids.includes(i.id) ? { ...i, visible: false } : i)); items.map(i => (ids.includes(i.id) ? { ...i, visible: false } : i));
@@ -1,6 +1,6 @@
import { ALL_NAV_ITEMS } from '../../config/navItems'; import { ALL_NAV_ITEMS } from '@/config/navItems';
import { CONSERVED_SIDEBAR_NAV_IDS, type SidebarItemConfig } from '../../store/sidebarStore'; import { CONSERVED_SIDEBAR_NAV_IDS, type SidebarItemConfig } from '@/features/sidebar/store/sidebarStore';
import { applyListReorderById, type ListReorderDropTarget } from './listReorder'; import { applyListReorderById, type ListReorderDropTarget } from '@/utils/componentHelpers/listReorder';
export type SidebarNavSection = 'library' | 'system'; export type SidebarNavSection = 'library' | 'system';