refactor(hooks): move cross-cutting hooks into lib/hooks

The five residual src/hooks/ hooks (useConnectionStatus, useCardGridMetrics,
useTracklistColumns, useNavidromeAdminRole, useAnalysisPerfListener) are all
domain-agnostic — none imports @/features — so they join the other shared hooks
in src/lib/hooks/ (with their two colocated tests). Consumers repointed;
relative-up imports in the moved files become the @/ alias. src/hooks/ is removed.

Pure move + import updates, no behavior change. The layering baseline gains five
lib->store entries (the three hooks that read authStore/devOfflineBrowseStore are
only now caught under lib/) — same documented debt class as the api move.
This commit is contained in:
Psychotoxical
2026-07-01 14:38:23 +02:00
parent 25055dc79a
commit f2cf8a08df
38 changed files with 120 additions and 35 deletions
+85
View File
@@ -533,6 +533,91 @@
"name": "lib-is-the-floor" "name": "lib-is-the-floor"
} }
}, },
{
"type": "dependency",
"from": "src/lib/hooks/useCardGridMetrics.ts",
"to": "src/store/authStore.ts",
"unresolvedTo": "@/store/authStore",
"dependencyTypes": [
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-paths",
"local",
"import"
],
"rule": {
"severity": "error",
"name": "lib-is-the-floor"
}
},
{
"type": "dependency",
"from": "src/lib/hooks/useCardGridMetrics.ts",
"to": "src/store/authStoreHelpers.ts",
"unresolvedTo": "@/store/authStoreHelpers",
"dependencyTypes": [
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-paths",
"local",
"import"
],
"rule": {
"severity": "error",
"name": "lib-is-the-floor"
}
},
{
"type": "dependency",
"from": "src/lib/hooks/useConnectionStatus.ts",
"to": "src/store/authStore.ts",
"unresolvedTo": "@/store/authStore",
"dependencyTypes": [
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-paths",
"local",
"import"
],
"rule": {
"severity": "error",
"name": "lib-is-the-floor"
}
},
{
"type": "dependency",
"from": "src/lib/hooks/useConnectionStatus.ts",
"to": "src/store/devOfflineBrowseStore.ts",
"unresolvedTo": "@/store/devOfflineBrowseStore",
"dependencyTypes": [
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-paths",
"local",
"import"
],
"rule": {
"severity": "error",
"name": "lib-is-the-floor"
}
},
{
"type": "dependency",
"from": "src/lib/hooks/useNavidromeAdminRole.ts",
"to": "src/store/authStore.ts",
"unresolvedTo": "@/store/authStore",
"dependencyTypes": [
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-paths",
"local",
"import"
],
"rule": {
"severity": "error",
"name": "lib-is-the-floor"
}
},
{ {
"type": "dependency", "type": "dependency",
"from": "src/lib/library/hooks/useLibraryAnalysisBackfill.ts", "from": "src/lib/library/hooks/useLibraryAnalysisBackfill.ts",
+1 -1
View File
@@ -55,7 +55,7 @@ import { useOfflineAutoNav } from '@/features/offline';
import { useOfflineLibraryFilterSuspend } from '@/features/offline'; import { useOfflineLibraryFilterSuspend } from '@/features/offline';
import { AppShellQueueResizerSeam } from '@/app/AppShellQueueResizerSeam'; import { AppShellQueueResizerSeam } from '@/app/AppShellQueueResizerSeam';
import { IS_LINUX, IS_MACOS } from '@/lib/util/platform'; import { IS_LINUX, IS_MACOS } from '@/lib/util/platform';
import { useConnectionStatus } from '../hooks/useConnectionStatus'; import { useConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { useIdlePlayQueuePull } from '@/app/hooks/useIdlePlayQueuePull'; import { useIdlePlayQueuePull } from '@/app/hooks/useIdlePlayQueuePull';
import { useAuthStore } from '../store/authStore'; import { useAuthStore } from '../store/authStore';
import { usePlayerStore } from '@/features/playback/store/playerStore'; import { usePlayerStore } from '@/features/playback/store/playerStore';
+1 -1
View File
@@ -4,7 +4,7 @@ import { createPortal } from 'react-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Check, ChevronDown, RefreshCw } from 'lucide-react'; import { Check, ChevronDown, RefreshCw } from 'lucide-react';
import type { ConnectionStatus } from '@/hooks/useConnectionStatus'; import type { ConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { usePlayQueueSyncLedState } from '@/app/hooks/usePlayQueueSyncLedState'; import { usePlayQueueSyncLedState } from '@/app/hooks/usePlayQueueSyncLedState';
import type { ServerProfile } from '@/store/authStoreTypes'; import type { ServerProfile } from '@/store/authStoreTypes';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
+1 -1
View File
@@ -30,7 +30,7 @@ import {
resolveOverlayVisibility, resolveOverlayVisibility,
usePerfOverlayMode, usePerfOverlayMode,
} from '@/lib/perf/perfOverlayMode'; } from '@/lib/perf/perfOverlayMode';
import { useAnalysisPerfListener } from '@/hooks/useAnalysisPerfListener'; import { useAnalysisPerfListener } from '@/lib/hooks/useAnalysisPerfListener';
import { useCoverPerfListener } from '@/cover/useCoverPerfListener'; import { useCoverPerfListener } from '@/cover/useCoverPerfListener';
import { getCoverCachedPerMinute, getCoverUiPerMinute } from '@/lib/perf/coverPerfStore'; import { getCoverCachedPerMinute, getCoverUiPerMinute } from '@/lib/perf/coverPerfStore';
+1 -1
View File
@@ -11,7 +11,7 @@ import {
markPlaybackIdle, markPlaybackIdle,
} from '@/features/playback/store/queuePlaybackIdle'; } from '@/features/playback/store/queuePlaybackIdle';
import { hasPendingQueueSync } from '@/features/playback/store/queueSync'; import { hasPendingQueueSync } from '@/features/playback/store/queueSync';
import type { ConnectionStatus } from '@/hooks/useConnectionStatus'; import type { ConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { canAutoIdlePlayQueuePull } from '@/app/hooks/usePlayQueueSyncLedState'; import { canAutoIdlePlayQueuePull } from '@/app/hooks/usePlayQueueSyncLedState';
const IDLE_THRESHOLD_MS = 30_000; const IDLE_THRESHOLD_MS = 30_000;
+1 -1
View File
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from 'react'; import { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import type { ConnectionStatus } from '@/hooks/useConnectionStatus'; import type { ConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { pullPlayQueueFromActiveServer } from '@/features/playback/store/applyServerPlayQueue'; import { pullPlayQueueFromActiveServer } from '@/features/playback/store/applyServerPlayQueue';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { useOrbitStore } from '@/features/orbit'; import { useOrbitStore } from '@/features/orbit';
@@ -1,7 +1,7 @@
import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import type { Track } from '@/lib/media/trackTypes'; import type { Track } from '@/lib/media/trackTypes';
import React, { useMemo, useState, useEffect } from 'react'; import React, { useMemo, useState, useEffect } from 'react';
import { useTracklistColumns } from '@/hooks/useTracklistColumns'; import { useTracklistColumns } from '@/lib/hooks/useTracklistColumns';
import { usePlayerStore } from '@/features/playback/store/playerStore'; import { usePlayerStore } from '@/features/playback/store/playerStore';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useIsMobile } from '@/lib/hooks/useIsMobile'; import { useIsMobile } from '@/lib/hooks/useIsMobile';
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react';
import { AudioLines, ChevronRight, Heart, Play, Square } from 'lucide-react'; import { AudioLines, ChevronRight, Heart, Play, Square } from 'lucide-react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import type { Track } from '@/lib/media/trackTypes'; import type { Track } from '@/lib/media/trackTypes';
import { songToTrack } from '@/lib/media/songToTrack'; import { songToTrack } from '@/lib/media/songToTrack';
@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
import { CENTERED_COLS, isSortable, type ColKey, type SortKey } from '@/features/album/utils/albumTrackListHelpers'; import { CENTERED_COLS, isSortable, type ColKey, type SortKey } from '@/features/album/utils/albumTrackListHelpers';
interface Props { interface Props {
@@ -1,4 +1,4 @@
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
export function codecLabel(song: { suffix?: string; bitRate?: number }, showBitrate: boolean): string { export function codecLabel(song: { suffix?: string; bitRate?: number }, showBitrate: boolean): string {
const parts: string[] = []; const parts: string[] = [];
@@ -6,7 +6,7 @@ import type {
SubsonicAlbum, SubsonicArtist, SubsonicArtistInfo, SubsonicSong, SubsonicAlbum, SubsonicArtist, SubsonicArtistInfo, SubsonicSong,
} from '@/lib/api/subsonicTypes'; } from '@/lib/api/subsonicTypes';
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { useConnectionStatus } from '@/hooks/useConnectionStatus'; import { useConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { loadArtistFromLibraryIndex } from '@/features/offline'; import { loadArtistFromLibraryIndex } from '@/features/offline';
import { useOfflineBrowseContext } from '@/features/offline'; import { useOfflineBrowseContext } from '@/features/offline';
import { loadArtistFromLocalPlayback, offlineLocalBrowseEnabled } from '@/features/offline'; import { loadArtistFromLocalPlayback, offlineLocalBrowseEnabled } from '@/features/offline';
@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { AudioLines, ChevronRight, Play, Square, X } from 'lucide-react'; import { AudioLines, ChevronRight, Play, Square, X } from 'lucide-react';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import { codecLabel } from '@/lib/format/playlistDetailHelpers'; import { codecLabel } from '@/lib/format/playlistDetailHelpers';
import { formatLastSeen } from '@/lib/format/userMgmtHelpers'; import { formatLastSeen } from '@/lib/format/userMgmtHelpers';
@@ -4,7 +4,7 @@ import FavoriteSongRow, { type FavoriteSongRowCallbacks } from '@/features/favor
import { TracklistColumnPicker } from '@/ui/TracklistColumnPicker'; import { TracklistColumnPicker } from '@/ui/TracklistColumnPicker';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import { usePlayerStore } from '@/features/playback/store/playerStore'; import { usePlayerStore } from '@/features/playback/store/playerStore';
import { previewInputFromSong, usePreviewStore } from '@/features/playback/store/previewStore'; import { previewInputFromSong, usePreviewStore } from '@/features/playback/store/previewStore';
@@ -7,7 +7,7 @@ import type {
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { usePlayerStore } from '@/features/playback/store/playerStore'; import { usePlayerStore } from '@/features/playback/store/playerStore';
import type { TopFavoriteArtist } from '@/features/favorites/components/TopFavoriteArtists'; import type { TopFavoriteArtist } from '@/features/favorites/components/TopFavoriteArtists';
import { useConnectionStatus } from '@/hooks/useConnectionStatus'; import { useConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { isActiveServerReachable } from '@/lib/network/activeServerReachability'; import { isActiveServerReachable } from '@/lib/network/activeServerReachability';
import { useOfflineBrowseContext } from '@/features/offline'; import { useOfflineBrowseContext } from '@/features/offline';
import { useOfflineBrowseReloadToken } from '@/features/offline'; import { useOfflineBrowseReloadToken } from '@/features/offline';
+1 -1
View File
@@ -1,6 +1,6 @@
import { queueSongStar, queueSongRating } from '@/features/playback/store/pendingStarSync'; import { queueSongStar, queueSongRating } from '@/features/playback/store/pendingStarSync';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { useTracklistColumns, type ColDef } from '@/hooks/useTracklistColumns'; import { useTracklistColumns, type ColDef } from '@/lib/hooks/useTracklistColumns';
import { TopFavoriteArtistsRow } from '@/features/favorites/components/TopFavoriteArtists'; import { TopFavoriteArtistsRow } from '@/features/favorites/components/TopFavoriteArtists';
import { RadioStationRow } from '@/features/favorites/components/RadioFavorites'; import { RadioStationRow } from '@/features/favorites/components/RadioFavorites';
import FavoritesSongsSectionHeader from '@/features/favorites/components/FavoritesSongsSectionHeader'; import FavoritesSongsSectionHeader from '@/features/favorites/components/FavoritesSongsSectionHeader';
+1 -1
View File
@@ -28,7 +28,7 @@ import {
writeHomeFeedCache, writeHomeFeedCache,
type HomeFeedSnapshot, type HomeFeedSnapshot,
} from '@/features/home/store/homeFeedCache'; } from '@/features/home/store/homeFeedCache';
import { useConnectionStatus } from '@/hooks/useConnectionStatus'; import { useConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { useOfflineBrowseContext } from '@/features/offline'; import { useOfflineBrowseContext } from '@/features/offline';
import { useOfflineBrowseReloadToken } from '@/features/offline'; import { useOfflineBrowseReloadToken } from '@/features/offline';
import { useDevOfflineBrowseStore } from '@/features/offline'; import { useDevOfflineBrowseStore } from '@/features/offline';
@@ -7,7 +7,7 @@ import type { ArtistStats, TrackStats } from '@/music-network';
import { getMusicNetworkRuntimeOrNull } from '@/music-network'; import { getMusicNetworkRuntimeOrNull } from '@/music-network';
import { makeCache } from '@/lib/cache/nowPlayingCache'; import { makeCache } from '@/lib/cache/nowPlayingCache';
import { shouldAttemptSubsonicForServer } from '@/lib/network/subsonicNetworkGuard'; import { shouldAttemptSubsonicForServer } from '@/lib/network/subsonicNetworkGuard';
import { useConnectionStatus } from '@/hooks/useConnectionStatus'; import { useConnectionStatus } from '@/lib/hooks/useConnectionStatus';
// Module-level TTL caches (shared across mounts) // Module-level TTL caches (shared across mounts)
const songMetaCache = makeCache<SubsonicSong | null>(); const songMetaCache = makeCache<SubsonicSong | null>();
@@ -1,6 +1,6 @@
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { useOfflineStore } from '@/features/offline/store/offlineStore'; import { useOfflineStore } from '@/features/offline/store/offlineStore';
import { useConnectionStatus } from '@/hooks/useConnectionStatus'; import { useConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { usePlayerStatsRecordingEnabled } from '@/features/stats'; import { usePlayerStatsRecordingEnabled } from '@/features/stats';
import { hasOfflineBrowsingContent } from '@/features/offline/utils/favoritesOfflineBrowse'; import { hasOfflineBrowsingContent } from '@/features/offline/utils/favoritesOfflineBrowse';
import { useOfflineBrowseActive } from '@/features/offline/utils/offlineBrowseMode'; import { useOfflineBrowseActive } from '@/features/offline/utils/offlineBrowseMode';
@@ -1,4 +1,4 @@
import type { ConnectionStatus } from '@/hooks/useConnectionStatus'; import type { ConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import type { OfflineAlbumMeta } from '@/features/offline/store/offlineStore'; import type { OfflineAlbumMeta } from '@/features/offline/store/offlineStore';
import { favoritesOfflineBrowseEnabled } from '@/features/offline/utils/favoritesOfflineBrowse'; import { favoritesOfflineBrowseEnabled } from '@/features/offline/utils/favoritesOfflineBrowse';
import { hasOfflineBrowseCapability } from '@/features/offline/utils/offlineBrowseRouting'; import { hasOfflineBrowseCapability } from '@/features/offline/utils/offlineBrowseRouting';
@@ -2,7 +2,7 @@ import {
isDevOfflineBrowseForced, isDevOfflineBrowseForced,
useDevOfflineBrowseStore, useDevOfflineBrowseStore,
} from '@/store/devOfflineBrowseStore'; } from '@/store/devOfflineBrowseStore';
import { useConnectionStatus } from '@/hooks/useConnectionStatus'; import { useConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { isActiveServerReachable } from '@/lib/network/activeServerReachability'; import { isActiveServerReachable } from '@/lib/network/activeServerReachability';
/** True when browse/detail pages should use local-bytes-only data sources. */ /** True when browse/detail pages should use local-bytes-only data sources. */
@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { AudioLines, ChevronRight, Heart, Play, Square, Trash2 } from 'lucide-react'; import { AudioLines, ChevronRight, Heart, Play, Square, Trash2 } from 'lucide-react';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import { codecLabel } from '@/lib/format/playlistDetailHelpers'; import { codecLabel } from '@/lib/format/playlistDetailHelpers';
import { formatLastSeen } from '@/lib/format/userMgmtHelpers'; import { formatLastSeen } from '@/lib/format/userMgmtHelpers';
@@ -2,7 +2,7 @@ import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ChevronRight, Heart, Play, Plus, RefreshCw, Square } from 'lucide-react'; import { ChevronRight, Heart, Play, Plus, RefreshCw, Square } from 'lucide-react';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import { usePlayerStore } from '@/features/playback/store/playerStore'; import { usePlayerStore } from '@/features/playback/store/playerStore';
import { usePreviewStore } from '@/features/playback/store/previewStore'; import { usePreviewStore } from '@/features/playback/store/previewStore';
@@ -9,7 +9,7 @@ import { useNavigate } from 'react-router-dom';
import { import {
ListPlus, Search, Trash2, X, ListPlus, Search, Trash2, X,
} from 'lucide-react'; } from 'lucide-react';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
import type { SubsonicSong } from '@/lib/api/subsonicTypes'; import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import type { Track } from '@/lib/media/trackTypes'; import type { Track } from '@/lib/media/trackTypes';
import { usePlayerStore } from '@/features/playback/store/playerStore'; import { usePlayerStore } from '@/features/playback/store/playerStore';
@@ -2,7 +2,7 @@ import { updatePlaylist } from '@/lib/api/subsonicPlaylists';
import type { SubsonicPlaylist, SubsonicSong } from '@/lib/api/subsonicTypes'; import type { SubsonicPlaylist, SubsonicSong } from '@/lib/api/subsonicTypes';
import React, { useEffect, useState, useCallback, useMemo } from 'react'; import React, { useEffect, useState, useCallback, useMemo } from 'react';
import { useParams, useNavigate, useLocation } from 'react-router-dom'; import { useParams, useNavigate, useLocation } from 'react-router-dom';
import { useTracklistColumns, type ColDef } from '@/hooks/useTracklistColumns'; import { useTracklistColumns, type ColDef } from '@/lib/hooks/useTracklistColumns';
import { usePlayerStore } from '@/features/playback/store/playerStore'; import { usePlayerStore } from '@/features/playback/store/playerStore';
import { useShallow } from 'zustand/react/shallow'; import { useShallow } from 'zustand/react/shallow';
import { usePlaylistStore } from '@/features/playlist/store/playlistStore'; import { usePlaylistStore } from '@/features/playlist/store/playlistStore';
+1 -1
View File
@@ -15,7 +15,7 @@ import RadioEditModal from '@/features/radio/components/RadioEditModal';
import RadioDirectoryModal from '@/features/radio/components/RadioDirectoryModal'; import RadioDirectoryModal from '@/features/radio/components/RadioDirectoryModal';
import { usePerfProbeFlags } from '@/lib/perf/perfFlags'; import { usePerfProbeFlags } from '@/lib/perf/perfFlags';
import { VirtualCardGrid } from '@/ui/VirtualCardGrid'; import { VirtualCardGrid } from '@/ui/VirtualCardGrid';
import { useNavidromeAdminRole, canManageNavidromeRadio } from '@/hooks/useNavidromeAdminRole'; import { useNavidromeAdminRole, canManageNavidromeRadio } from '@/lib/hooks/useNavidromeAdminRole';
export default function InternetRadio() { export default function InternetRadio() {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -1,7 +1,7 @@
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import { usePlayerStore } from '@/features/playback/store/playerStore'; import { usePlayerStore } from '@/features/playback/store/playerStore';
import { useConnectionStatus } from '@/hooks/useConnectionStatus'; import { useConnectionStatus } from '@/lib/hooks/useConnectionStatus';
import { useNavidromeAdminRole } from '@/hooks/useNavidromeAdminRole'; import { useNavidromeAdminRole } from '@/lib/hooks/useNavidromeAdminRole';
import { serverListDisplayLabel } from '@/lib/server/serverDisplayName'; import { serverListDisplayLabel } from '@/lib/server/serverDisplayName';
import { findServerByIdOrIndexKey } from '@/lib/server/serverLookup'; import { findServerByIdOrIndexKey } from '@/lib/server/serverLookup';
import { PerfProbeMetricSection } from '@/features/sidebar/components/perfProbe/PerfProbeMetricCard'; import { PerfProbeMetricSection } from '@/features/sidebar/components/perfProbe/PerfProbeMetricCard';
@@ -1,5 +1,5 @@
import { useAuthStore } from '@/store/authStore'; import { useAuthStore } from '@/store/authStore';
import type { NavidromeAdminRole } from '@/hooks/useNavidromeAdminRole'; import type { NavidromeAdminRole } from '@/lib/hooks/useNavidromeAdminRole';
import { isNavidromeServer, formatServerSoftware } from '@/lib/server/subsonicServerIdentity'; import { isNavidromeServer, formatServerSoftware } from '@/lib/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 {
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
import { acquirePerfLivePoll, patchPerfLiveAnalysis } from '@/lib/perf/perfLiveStore'; import { acquirePerfLivePoll, patchPerfLiveAnalysis } from '@/lib/perf/perfLiveStore';
import { setPerfProbeTelemetryActive } from '@/lib/perf/perfTelemetry'; import { setPerfProbeTelemetryActive } from '@/lib/perf/perfTelemetry';
import { useAnalysisPerfLast } from '@/lib/perf/analysisPerfStore'; import { useAnalysisPerfLast } from '@/lib/perf/analysisPerfStore';
import { useAnalysisPerfListener } from '@/hooks/useAnalysisPerfListener'; import { useAnalysisPerfListener } from '@/lib/hooks/useAnalysisPerfListener';
import { useCoverPerfListener, useCoverUiThroughputPoll } from '@/cover/useCoverPerfListener'; import { useCoverPerfListener, useCoverUiThroughputPoll } from '@/cover/useCoverPerfListener';
import { import {
getPerfProbeFlags, getPerfProbeFlags,
@@ -1,6 +1,6 @@
import { useLayoutEffect, useState, type RefObject } from 'react'; import { useLayoutEffect, useState, type RefObject } from 'react';
import { useAuthStore } from '../store/authStore'; import { useAuthStore } from '@/store/authStore';
import { clampLibraryGridMaxColumns } from '../store/authStoreHelpers'; import { clampLibraryGridMaxColumns } from '@/store/authStoreHelpers';
import { import {
type CardGridRowHeightVariant, type CardGridRowHeightVariant,
computeCardGridColumnCount, computeCardGridColumnCount,
@@ -1,5 +1,5 @@
import { useState, useEffect, useCallback, useRef, useMemo, useSyncExternalStore } from 'react'; import { useState, useEffect, useCallback, useRef, useMemo, useSyncExternalStore } from 'react';
import { useAuthStore } from '../store/authStore'; import { useAuthStore } from '@/store/authStore';
import { scheduleInstantMixProbeForServer } from '@/lib/api/subsonic'; import { scheduleInstantMixProbeForServer } from '@/lib/api/subsonic';
import { serverListDisplayLabel } from '@/lib/server/serverDisplayName'; import { serverListDisplayLabel } from '@/lib/server/serverDisplayName';
import { import {
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { ndLogin } from '@/lib/api/navidromeAdmin'; import { ndLogin } from '@/lib/api/navidromeAdmin';
import { useAuthStore } from '../store/authStore'; import { useAuthStore } from '@/store/authStore';
import { isNavidromeServer } from '@/lib/server/subsonicServerIdentity'; import { isNavidromeServer } from '@/lib/server/subsonicServerIdentity';
export type NavidromeAdminRole = 'idle' | 'checking' | 'admin' | 'user' | 'na' | 'error'; export type NavidromeAdminRole = 'idle' | 'checking' | 'admin' | 'user' | 'na' | 'error';
+1 -1
View File
@@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import { renderWithProviders } from '@/test/helpers/renderWithProviders'; import { renderWithProviders } from '@/test/helpers/renderWithProviders';
import { TracklistColumnPicker } from '@/ui/TracklistColumnPicker'; import { TracklistColumnPicker } from '@/ui/TracklistColumnPicker';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
const COLUMNS: readonly ColDef[] = [ const COLUMNS: readonly ColDef[] = [
{ key: 'title', i18nKey: 'title', minWidth: 100, defaultWidth: 200, required: true }, { key: 'title', i18nKey: 'title', minWidth: 100, defaultWidth: 200, required: true },
+1 -1
View File
@@ -2,7 +2,7 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { Check, ChevronDown, RotateCcw } from 'lucide-react'; import { Check, ChevronDown, RotateCcw } from 'lucide-react';
import type { TFunction } from 'i18next'; import type { TFunction } from 'i18next';
import type { ColDef } from '@/hooks/useTracklistColumns'; import type { ColDef } from '@/lib/hooks/useTracklistColumns';
interface Props { interface Props {
/** Every column (required ones are filtered out of the menu). */ /** Every column (required ones are filtered out of the menu). */
+1 -1
View File
@@ -4,7 +4,7 @@ import { useWarmGridCovers } from '@/cover/useWarmGridCovers';
import { useVirtualizer } from '@tanstack/react-virtual'; import { useVirtualizer } from '@tanstack/react-virtual';
import { APP_MAIN_SCROLL_VIEWPORT_ID } from '@/constants/appScroll'; import { APP_MAIN_SCROLL_VIEWPORT_ID } from '@/constants/appScroll';
import { useElementClientHeightById } from '@/lib/hooks/useResizeClientHeight'; import { useElementClientHeightById } from '@/lib/hooks/useResizeClientHeight';
import { useCardGridMetrics } from '@/hooks/useCardGridMetrics'; import { useCardGridMetrics } from '@/lib/hooks/useCardGridMetrics';
import { useRemeasureGridVirtualizer } from '@/lib/hooks/useRemeasureGridVirtualizer'; import { useRemeasureGridVirtualizer } from '@/lib/hooks/useRemeasureGridVirtualizer';
import { useVirtualizerScrollMargin } from '@/lib/hooks/useVirtualizerScrollMargin'; import { useVirtualizerScrollMargin } from '@/lib/hooks/useVirtualizerScrollMargin';
import type { CardGridRowHeightVariant } from '@/lib/util/cardGridLayout'; import type { CardGridRowHeightVariant } from '@/lib/util/cardGridLayout';