From 15a6590e77f2a1f8dfa08a9504d0cc6ca2cead68 Mon Sep 17 00:00:00 2001 From: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com> Date: Tue, 30 Jun 2026 19:12:26 +0200 Subject: [PATCH] refactor(updater+contextMenu): co-locate updater feature (AppUpdater+Changelog) and the context-menu subsystem into features/ --- src/app/AppShell.tsx | 4 ++-- .../album/components/AlbumDetailToolbar.tsx | 2 +- .../components}/AddToPlaylistSubmenu.tsx | 4 ++-- .../components}/AlbumArtistToPlaylistSubmenu.tsx | 2 +- .../components}/AlbumContextItems.tsx | 6 +++--- .../components}/ArtistContextItems.tsx | 6 +++--- .../contextMenu}/components/ContextMenu.test.tsx | 2 +- .../contextMenu}/components/ContextMenu.tsx | 16 ++++++++-------- .../contextMenu/components}/ContextMenuItems.tsx | 12 ++++++------ .../components}/MoveToFolderSubmenu.tsx | 2 +- .../components}/MultiAlbumToPlaylistSubmenu.tsx | 4 ++-- .../components}/MultiArtistToPlaylistSubmenu.tsx | 4 ++-- .../components}/PlaylistContextItems.tsx | 10 +++++----- .../components}/PlaylistToPlaylistSubmenus.tsx | 4 ++-- .../components}/QueueItemContextItems.tsx | 10 +++++----- .../contextMenu/components}/SongContextItems.tsx | 14 +++++++------- .../components}/contextMenuItemTypes.ts | 2 +- src/features/contextMenu/index.ts | 8 ++++++++ .../components/FavoritesSongsSectionHeader.tsx | 2 +- .../components/PlaylistSongSearchPanel.tsx | 2 +- .../playlist/components/PlaylistTracklist.tsx | 2 +- .../updater}/components/AppUpdater.tsx | 8 ++++---- .../updater/components}/Changelog.tsx | 0 src/features/updater/index.ts | 5 +++++ 24 files changed, 72 insertions(+), 59 deletions(-) rename src/{components/contextMenu => features/contextMenu/components}/AddToPlaylistSubmenu.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/AlbumArtistToPlaylistSubmenu.tsx (96%) rename src/{components/contextMenu => features/contextMenu/components}/AlbumContextItems.tsx (97%) rename src/{components/contextMenu => features/contextMenu/components}/ArtistContextItems.tsx (96%) rename src/{ => features/contextMenu}/components/ContextMenu.test.tsx (99%) rename src/{ => features/contextMenu}/components/ContextMenu.tsx (94%) rename src/{components/contextMenu => features/contextMenu/components}/ContextMenuItems.tsx (54%) rename src/{components/contextMenu => features/contextMenu/components}/MoveToFolderSubmenu.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/MultiAlbumToPlaylistSubmenu.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/MultiArtistToPlaylistSubmenu.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/PlaylistContextItems.tsx (94%) rename src/{components/contextMenu => features/contextMenu/components}/PlaylistToPlaylistSubmenus.tsx (98%) rename src/{components/contextMenu => features/contextMenu/components}/QueueItemContextItems.tsx (93%) rename src/{components/contextMenu => features/contextMenu/components}/SongContextItems.tsx (97%) rename src/{components/contextMenu => features/contextMenu/components}/contextMenuItemTypes.ts (97%) create mode 100644 src/features/contextMenu/index.ts rename src/{ => features/updater}/components/AppUpdater.tsx (97%) rename src/{components/appUpdater => features/updater/components}/Changelog.tsx (100%) create mode 100644 src/features/updater/index.ts diff --git a/src/app/AppShell.tsx b/src/app/AppShell.tsx index 8adc99f3..bfb90fd4 100644 --- a/src/app/AppShell.tsx +++ b/src/app/AppShell.tsx @@ -15,7 +15,7 @@ import { NowPlayingDropdown } from '@/features/nowPlaying'; import QueuePanel from '@/features/queue'; import AppRoutes from './AppRoutes'; import FullscreenPlayer from '@/features/fullscreenPlayer'; -import ContextMenu from '../components/ContextMenu'; +import ContextMenu from '@/features/contextMenu/components/ContextMenu'; import SongInfoModal from '../components/SongInfoModal'; import { DownloadFolderModal } from '@/features/offline'; import GlobalConfirmModal from '../components/GlobalConfirmModal'; @@ -30,7 +30,7 @@ import { import ConnectionIndicator from '@/app/ConnectionIndicator'; import MusicNetworkIndicator from '../components/MusicNetworkIndicator'; import { OfflineBanner } from '@/features/offline'; -import AppUpdater from '../components/AppUpdater'; +import AppUpdater from '@/features/updater/components/AppUpdater'; import TitleBar from '@/app/TitleBar'; import { OrbitSessionBar, OrbitStartTrigger } from '@/features/orbit'; import { useOrbitHost } from '@/features/orbit'; diff --git a/src/features/album/components/AlbumDetailToolbar.tsx b/src/features/album/components/AlbumDetailToolbar.tsx index 15fe4e8b..6eab478b 100644 --- a/src/features/album/components/AlbumDetailToolbar.tsx +++ b/src/features/album/components/AlbumDetailToolbar.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { ListPlus, Search, X } from 'lucide-react'; import type { TFunction } from 'i18next'; import { useSelectionStore } from '@/store/selectionStore'; -import { AddToPlaylistSubmenu } from '@/components/ContextMenu'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/ContextMenu'; import { offlineActionPolicy, type OfflineActionPolicy } from '@/features/offline'; interface Props { diff --git a/src/components/contextMenu/AddToPlaylistSubmenu.tsx b/src/features/contextMenu/components/AddToPlaylistSubmenu.tsx similarity index 98% rename from src/components/contextMenu/AddToPlaylistSubmenu.tsx rename to src/features/contextMenu/components/AddToPlaylistSubmenu.tsx index 98e0d216..d22f899d 100644 --- a/src/components/contextMenu/AddToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/AddToPlaylistSubmenu.tsx @@ -4,11 +4,11 @@ import { ListMusic, Plus } from 'lucide-react'; import { getPlaylist, updatePlaylist } from '@/lib/api/subsonicPlaylists'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { usePlaylistStore } from '@/features/playlist'; -import { showToast } from '../../utils/ui/toast'; +import { showToast } from '@/utils/ui/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '../../utils/componentHelpers/contextMenuHelpers'; +} from '@/utils/componentHelpers/contextMenuHelpers'; interface Props { songIds: string[]; diff --git a/src/components/contextMenu/AlbumArtistToPlaylistSubmenu.tsx b/src/features/contextMenu/components/AlbumArtistToPlaylistSubmenu.tsx similarity index 96% rename from src/components/contextMenu/AlbumArtistToPlaylistSubmenu.tsx rename to src/features/contextMenu/components/AlbumArtistToPlaylistSubmenu.tsx index 9f962fc9..3b3bc3f4 100644 --- a/src/components/contextMenu/AlbumArtistToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/AlbumArtistToPlaylistSubmenu.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { resolveAlbum, resolveArtist, resolveMediaServerId } from '@/features/offline'; -import { AddToPlaylistSubmenu } from './AddToPlaylistSubmenu'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/AddToPlaylistSubmenu'; interface AlbumProps { albumId: string; diff --git a/src/components/contextMenu/AlbumContextItems.tsx b/src/features/contextMenu/components/AlbumContextItems.tsx similarity index 97% rename from src/components/contextMenu/AlbumContextItems.tsx rename to src/features/contextMenu/components/AlbumContextItems.tsx index 3a7f8a03..e673c78e 100644 --- a/src/components/contextMenu/AlbumContextItems.tsx +++ b/src/features/contextMenu/components/AlbumContextItems.tsx @@ -6,9 +6,9 @@ import { star, unstar } from '@/lib/api/subsonicStarRating'; import type { SubsonicAlbum } from '@/lib/api/subsonicTypes'; import { songToTrack } from '@/lib/media/songToTrack'; import StarRating from '@/ui/StarRating'; -import { AlbumToPlaylistSubmenu } from './AlbumArtistToPlaylistSubmenu'; -import { MultiAlbumToPlaylistSubmenu } from './MultiAlbumToPlaylistSubmenu'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; +import { AlbumToPlaylistSubmenu } from '@/features/contextMenu/components/AlbumArtistToPlaylistSubmenu'; +import { MultiAlbumToPlaylistSubmenu } from '@/features/contextMenu/components/MultiAlbumToPlaylistSubmenu'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; export default function AlbumContextItems(props: ContextMenuItemsProps) { const { diff --git a/src/components/contextMenu/ArtistContextItems.tsx b/src/features/contextMenu/components/ArtistContextItems.tsx similarity index 96% rename from src/components/contextMenu/ArtistContextItems.tsx rename to src/features/contextMenu/components/ArtistContextItems.tsx index da423e8d..5ef70a80 100644 --- a/src/components/contextMenu/ArtistContextItems.tsx +++ b/src/features/contextMenu/components/ArtistContextItems.tsx @@ -3,9 +3,9 @@ import { Radio, Heart, ChevronRight, ListMusic, Star, Share2 } from 'lucide-reac import { star, unstar } from '@/lib/api/subsonicStarRating'; import type { SubsonicArtist } from '@/lib/api/subsonicTypes'; import StarRating from '@/ui/StarRating'; -import { ArtistToPlaylistSubmenu } from './AlbumArtistToPlaylistSubmenu'; -import { MultiArtistToPlaylistSubmenu } from './MultiArtistToPlaylistSubmenu'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; +import { ArtistToPlaylistSubmenu } from '@/features/contextMenu/components/AlbumArtistToPlaylistSubmenu'; +import { MultiArtistToPlaylistSubmenu } from '@/features/contextMenu/components/MultiArtistToPlaylistSubmenu'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; export default function ArtistContextItems(props: ContextMenuItemsProps) { const { diff --git a/src/components/ContextMenu.test.tsx b/src/features/contextMenu/components/ContextMenu.test.tsx similarity index 99% rename from src/components/ContextMenu.test.tsx rename to src/features/contextMenu/components/ContextMenu.test.tsx index 9577590c..29e1601b 100644 --- a/src/components/ContextMenu.test.tsx +++ b/src/features/contextMenu/components/ContextMenu.test.tsx @@ -51,7 +51,7 @@ vi.mock('@/features/offline/hooks/useOfflineBrowseContext', () => ({ }), })); -import ContextMenu from './ContextMenu'; +import ContextMenu from '@/features/contextMenu/components/ContextMenu'; import { renderWithProviders } from '@/test/helpers/renderWithProviders'; import { usePlayerStore } from '@/features/playback/store/playerStore'; import { useAuthStore } from '@/store/authStore'; diff --git a/src/components/ContextMenu.tsx b/src/features/contextMenu/components/ContextMenu.tsx similarity index 94% rename from src/components/ContextMenu.tsx rename to src/features/contextMenu/components/ContextMenu.tsx index a0b91dd1..ccf780d4 100644 --- a/src/components/ContextMenu.tsx +++ b/src/features/contextMenu/components/ContextMenu.tsx @@ -3,26 +3,26 @@ import type { Track } from '@/lib/media/trackTypes'; import { useOrbitStore } from '@/features/orbit'; import { usePlayerStore } from '@/features/playback/store/playerStore'; import { useShallow } from 'zustand/react/shallow'; -import { useAuthStore } from '../store/authStore'; +import { useAuthStore } from '@/store/authStore'; import { useTranslation } from 'react-i18next'; -import type { EntityShareKind } from '../utils/share/shareLink'; -import { AddToPlaylistSubmenu } from './contextMenu/AddToPlaylistSubmenu'; +import type { EntityShareKind } from '@/utils/share/shareLink'; +import { AddToPlaylistSubmenu } from '@/features/contextMenu/components/AddToPlaylistSubmenu'; import { copyShareLink as copyShareLinkAction, downloadAlbum as downloadAlbumAction, startInstantMix as startInstantMixAction, startRadio as startRadioAction, -} from '../utils/componentHelpers/contextMenuActions'; -import { useContextMenuKeyboardNav } from '../hooks/useContextMenuKeyboardNav'; -import { useContextMenuRating } from '../hooks/useContextMenuRating'; -import { usePlaybackLibraryNavigate } from '../hooks/usePlaybackLibraryNavigate'; +} from '@/utils/componentHelpers/contextMenuActions'; +import { useContextMenuKeyboardNav } from '@/hooks/useContextMenuKeyboardNav'; +import { useContextMenuRating } from '@/hooks/useContextMenuRating'; +import { usePlaybackLibraryNavigate } from '@/hooks/usePlaybackLibraryNavigate'; import { useNavigate } from 'react-router-dom'; import { useOfflineBrowseContext } from '@/features/offline'; import { offlineActionPolicy, type OfflineSurface, } from '@/features/offline'; -import ContextMenuItems from './contextMenu/ContextMenuItems'; +import ContextMenuItems from '@/features/contextMenu/components/ContextMenuItems'; function contextMenuSurfaceForType(type: string | null): OfflineSurface { switch (type) { diff --git a/src/components/contextMenu/ContextMenuItems.tsx b/src/features/contextMenu/components/ContextMenuItems.tsx similarity index 54% rename from src/components/contextMenu/ContextMenuItems.tsx rename to src/features/contextMenu/components/ContextMenuItems.tsx index 524b5456..e5b7e13b 100644 --- a/src/components/contextMenu/ContextMenuItems.tsx +++ b/src/features/contextMenu/components/ContextMenuItems.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; -import SongContextItems from './SongContextItems'; -import QueueItemContextItems from './QueueItemContextItems'; -import AlbumContextItems from './AlbumContextItems'; -import ArtistContextItems from './ArtistContextItems'; -import PlaylistContextItems from './PlaylistContextItems'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; +import SongContextItems from '@/features/contextMenu/components/SongContextItems'; +import QueueItemContextItems from '@/features/contextMenu/components/QueueItemContextItems'; +import AlbumContextItems from '@/features/contextMenu/components/AlbumContextItems'; +import ArtistContextItems from '@/features/contextMenu/components/ArtistContextItems'; +import PlaylistContextItems from '@/features/contextMenu/components/PlaylistContextItems'; export default function ContextMenuItems(props: ContextMenuItemsProps) { const { type } = props; diff --git a/src/components/contextMenu/MoveToFolderSubmenu.tsx b/src/features/contextMenu/components/MoveToFolderSubmenu.tsx similarity index 98% rename from src/components/contextMenu/MoveToFolderSubmenu.tsx rename to src/features/contextMenu/components/MoveToFolderSubmenu.tsx index bfaa2e66..85103424 100644 --- a/src/components/contextMenu/MoveToFolderSubmenu.tsx +++ b/src/features/contextMenu/components/MoveToFolderSubmenu.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Check, Folder, FolderMinus, Plus } from 'lucide-react'; -import { useAuthStore } from '../../store/authStore'; +import { useAuthStore } from '@/store/authStore'; import { EMPTY_SERVER_FOLDERS, usePlaylistFolderStore } from '@/features/playlist'; interface Props { diff --git a/src/components/contextMenu/MultiAlbumToPlaylistSubmenu.tsx b/src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx similarity index 98% rename from src/components/contextMenu/MultiAlbumToPlaylistSubmenu.tsx rename to src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx index 9c2272f0..14a22ca0 100644 --- a/src/components/contextMenu/MultiAlbumToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/MultiAlbumToPlaylistSubmenu.tsx @@ -4,11 +4,11 @@ import { ListMusic, Plus } from 'lucide-react'; import { resolveAlbum, resolveMediaServerId, resolvePlaylist } from '@/features/offline'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { usePlaylistStore } from '@/features/playlist'; -import { showToast } from '../../utils/ui/toast'; +import { showToast } from '@/utils/ui/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '../../utils/componentHelpers/contextMenuHelpers'; +} from '@/utils/componentHelpers/contextMenuHelpers'; interface Props { albumIds: string[]; diff --git a/src/components/contextMenu/MultiArtistToPlaylistSubmenu.tsx b/src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx similarity index 98% rename from src/components/contextMenu/MultiArtistToPlaylistSubmenu.tsx rename to src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx index 096c8f32..b1e7cdf5 100644 --- a/src/components/contextMenu/MultiArtistToPlaylistSubmenu.tsx +++ b/src/features/contextMenu/components/MultiArtistToPlaylistSubmenu.tsx @@ -5,11 +5,11 @@ import { resolveAlbum, resolveArtist, resolveMediaServerId, resolvePlaylist } fr import { getPlaylists } from '@/lib/api/subsonicPlaylists'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { usePlaylistStore } from '@/features/playlist'; -import { showToast } from '../../utils/ui/toast'; +import { showToast } from '@/utils/ui/toast'; import { confirmAddAllDuplicates, isSmartPlaylistName, -} from '../../utils/componentHelpers/contextMenuHelpers'; +} from '@/utils/componentHelpers/contextMenuHelpers'; interface Props { artistIds: string[]; diff --git a/src/components/contextMenu/PlaylistContextItems.tsx b/src/features/contextMenu/components/PlaylistContextItems.tsx similarity index 94% rename from src/components/contextMenu/PlaylistContextItems.tsx rename to src/features/contextMenu/components/PlaylistContextItems.tsx index efb345f0..a8252d3c 100644 --- a/src/components/contextMenu/PlaylistContextItems.tsx +++ b/src/features/contextMenu/components/PlaylistContextItems.tsx @@ -2,9 +2,9 @@ import { useTranslation } from 'react-i18next'; import { Play, ChevronRight, FolderTree, ListMusic, Trash2 } from 'lucide-react'; import type { SubsonicPlaylist } from '@/lib/api/subsonicTypes'; import { usePlaylistStore } from '@/features/playlist'; -import { MultiPlaylistToPlaylistSubmenu, SinglePlaylistToPlaylistSubmenu } from './PlaylistToPlaylistSubmenus'; -import MoveToFolderSubmenu from './MoveToFolderSubmenu'; -import type { ContextMenuItemsProps } from './contextMenuItemTypes'; +import { MultiPlaylistToPlaylistSubmenu, SinglePlaylistToPlaylistSubmenu } from '@/features/contextMenu/components/PlaylistToPlaylistSubmenus'; +import MoveToFolderSubmenu from '@/features/contextMenu/components/MoveToFolderSubmenu'; +import type { ContextMenuItemsProps } from '@/features/contextMenu/components/contextMenuItemTypes'; export default function PlaylistContextItems(props: ContextMenuItemsProps) { const { @@ -64,7 +64,7 @@ export default function PlaylistContextItems(props: ContextMenuItemsProps) { <>