From 72e2e6dacaffb9ba25be0ff605c324d42776ba12 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Fri, 28 Nov 2025 22:30:10 -0800 Subject: [PATCH] update fields and add multiselect to smart playlist sort --- .../components/create-playlist-form.tsx | 9 ++++-- .../playlist-detail-song-list-header.tsx | 2 +- .../components/playlist-query-builder.tsx | 18 +++++------ .../playlist-detail-song-list-route.tsx | 31 ++++++++++++++----- src/shared/api/navidrome/navidrome-types.ts | 29 ++++++++++++----- 5 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/renderer/features/playlists/components/create-playlist-form.tsx b/src/renderer/features/playlists/components/create-playlist-form.tsx index ebb5e911b..deb1368ea 100644 --- a/src/renderer/features/playlists/components/create-playlist-form.tsx +++ b/src/renderer/features/playlists/components/create-playlist-form.tsx @@ -57,13 +57,18 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => { const smartPlaylist = queryBuilderRef.current?.getFilters(); + const sortValue = + isSmartPlaylist && smartPlaylist?.extraFilters?.sortBy + ? smartPlaylist.extraFilters.sortBy.join(',') + : undefined; + const rules = isSmartPlaylist && smartPlaylist?.filters ? { ...convertQueryGroupToNDQuery(smartPlaylist.filters), limit: smartPlaylist.extraFilters.limit, order: smartPlaylist.extraFilters.sortOrder, - sort: smartPlaylist.extraFilters.sortBy, + sort: sortValue || 'dateAdded', } : undefined; @@ -165,7 +170,7 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => { limit={undefined} query={undefined} ref={queryBuilderRef} - sortBy={SongListSort.ALBUM} + sortBy={[SongListSort.ALBUM]} sortOrder="asc" /> diff --git a/src/renderer/features/playlists/components/playlist-detail-song-list-header.tsx b/src/renderer/features/playlists/components/playlist-detail-song-list-header.tsx index c58d616e4..b29d1bdaa 100644 --- a/src/renderer/features/playlists/components/playlist-detail-song-list-header.tsx +++ b/src/renderer/features/playlists/components/playlist-detail-song-list-header.tsx @@ -53,7 +53,7 @@ export const PlaylistDetailSongListHeader = ({ {formatDurationString(playlistDuration)} )} - + {itemCount} diff --git a/src/renderer/features/playlists/components/playlist-query-builder.tsx b/src/renderer/features/playlists/components/playlist-query-builder.tsx index ae0bddb43..12ffcb9d5 100644 --- a/src/renderer/features/playlists/components/playlist-query-builder.tsx +++ b/src/renderer/features/playlists/components/playlist-query-builder.tsx @@ -30,6 +30,7 @@ import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu'; import { Flex } from '/@/shared/components/flex/flex'; import { Group } from '/@/shared/components/group/group'; import { Icon } from '/@/shared/components/icon/icon'; +import { MultiSelect } from '/@/shared/components/multi-select/multi-select'; import { NumberInput } from '/@/shared/components/number-input/number-input'; import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area'; import { Select } from '/@/shared/components/select/select'; @@ -52,15 +53,15 @@ interface PlaylistQueryBuilderProps { limit?: number; onSave?: ( parsedFilter: any, - extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, + extraFilters: { limit?: number; sortBy?: string[]; sortOrder?: string }, ) => void; onSaveAs?: ( parsedFilter: any, - extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, + extraFilters: { limit?: number; sortBy?: string[]; sortOrder?: string }, ) => void; playlistId?: string; query: any; - sortBy: SongListSort; + sortBy: SongListSort | SongListSort[]; sortOrder: 'asc' | 'desc'; } @@ -82,7 +83,7 @@ export type PlaylistQueryBuilderRef = { getFilters: () => { extraFilters: { limit?: number; - sortBy?: string; + sortBy?: string[]; sortOrder?: string; }; filters: QueryBuilderGroup; @@ -133,7 +134,7 @@ export const PlaylistQueryBuilder = forwardRef( const extraFiltersForm = useForm({ initialValues: { limit, - sortBy, + sortBy: Array.isArray(sortBy) ? sortBy : sortBy ? [sortBy] : [], sortOrder, }, }); @@ -442,13 +443,12 @@ export const PlaylistQueryBuilder = forwardRef( /> - - { const handleSave = ( filter: Record, - extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, + extraFilters: { limit?: number; sortBy?: string[]; sortOrder?: string }, ) => { if (!detailQuery?.data) return; + const sortValue = + extraFilters.sortBy && extraFilters.sortBy.length > 0 + ? extraFilters.sortBy.join(',') + : 'dateAdded'; + const rules = { ...filter, limit: extraFilters.limit || undefined, order: extraFilters.sortOrder || 'desc', - sort: extraFilters.sortBy || 'dateAdded', + sort: sortValue, }; createPlaylistMutation.mutate( @@ -89,15 +94,20 @@ const PlaylistDetailSongListRoute = () => { const handleSaveAs = ( filter: Record, - extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, + extraFilters: { limit?: number; sortBy?: string[]; sortOrder?: string }, ) => { if (!detailQuery?.data) return; + const sortValue = + extraFilters.sortBy && extraFilters.sortBy.length > 0 + ? extraFilters.sortBy.join(',') + : 'dateAdded'; + const rules = { ...filter, limit: extraFilters.limit || undefined, order: extraFilters.sortOrder || 'desc', - sort: extraFilters.sortBy || 'dateAdded', + sort: sortValue, }; openModal({ @@ -255,9 +265,16 @@ const PlaylistDetailSongListRoute = () => { onSaveAs={handleSaveAs} playlistId={playlistId} query={detailQuery?.data?.rules} - sortBy={ - detailQuery?.data?.rules?.sort || SongListSort.ALBUM - } + sortBy={(() => { + const sort = detailQuery?.data?.rules?.sort; + if (Array.isArray(sort)) { + return sort; + } + if (typeof sort === 'string' && sort.includes(',')) { + return sort.split(',').map((s) => s.trim()); + } + return sort ? [sort] : [SongListSort.ALBUM]; + })()} sortOrder={detailQuery?.data?.rules?.order || 'asc'} /> )} diff --git a/src/shared/api/navidrome/navidrome-types.ts b/src/shared/api/navidrome/navidrome-types.ts index 09a02ea07..a3e9f4e52 100644 --- a/src/shared/api/navidrome/navidrome-types.ts +++ b/src/shared/api/navidrome/navidrome-types.ts @@ -76,7 +76,9 @@ export const NDSongQueryFields = [ { label: 'Arranger', type: 'string', value: 'arranger' }, { label: 'Artist', type: 'string', value: 'artist' }, { label: 'Artists', type: 'string', value: 'artists' }, + { label: 'ASIN', type: 'string', value: 'asin' }, { label: 'Barcode', type: 'string', value: 'barcode' }, + { label: 'Bit Depth', type: 'number', value: 'bitdepth' }, { label: 'Bitrate', type: 'number', value: 'bitrate' }, { label: 'BPM', type: 'number', value: 'bpm' }, { label: 'Catalog Number', type: 'string', value: 'catalognumber' }, @@ -110,6 +112,7 @@ export const NDSongQueryFields = [ { label: 'Key', type: 'string', value: 'key' }, { label: 'Language', type: 'string', value: 'language' }, { label: 'License', type: 'string', value: 'license' }, + { label: 'Library Id', type: 'string', value: 'library_id' }, { label: 'Lyricist', type: 'string', value: 'lyricist' }, { label: 'Lyrics', type: 'string', value: 'lyrics' }, { label: 'Media', type: 'string', value: 'media' }, @@ -118,12 +121,24 @@ export const NDSongQueryFields = [ { label: 'Movement', type: 'string', value: 'movement' }, { label: 'Movement Name', type: 'string', value: 'movementname' }, { label: 'Movement Total', type: 'number', value: 'movementtotal' }, - { label: 'MusicBrainz Artist Id', type: 'string', value: 'musicbrainz_artistid' }, - { label: 'MusicBrainz Album Artist Id', type: 'string', value: 'musicbrainz_albumartistid' }, - { label: 'MusicBrainz Album Id', type: 'string', value: 'musicbrainz_albumid' }, + { label: 'MusicBrainz Album Artist Id', type: 'string', value: 'mbz_album_artist_id' }, + { label: 'MusicBrainz Album Id', type: 'string', value: 'mbz_album_id' }, + { label: 'MusicBrainz Artist Id', type: 'string', value: 'mbz_artist_id' }, + { label: 'MusicBrainz Arranger Id', type: 'string', value: 'musicbrainz_arrangerid' }, + { label: 'MusicBrainz Composer Id', type: 'string', value: 'musicbrainz_composerid' }, + { label: 'MusicBrainz Conductor Id', type: 'string', value: 'musicbrainz_conductorid' }, + { label: 'MusicBrainz Director Id', type: 'string', value: 'musicbrainz_directorid' }, { label: 'MusicBrainz Disc Id', type: 'string', value: 'musicbrainz_discid' }, - { label: 'MusicBrainz Recording Id', type: 'string', value: 'musicbrainz_recordingid' }, - { label: 'MusicBrainz Release Group Id', type: 'string', value: 'musicbrainz_releasegroupid' }, + { label: 'MusicBrainz DJ Mixer Id', type: 'string', value: 'musicbrainz_djmixerid' }, + { label: 'MusicBrainz Engineer Id', type: 'string', value: 'musicbrainz_engineerid' }, + { label: 'MusicBrainz Lyricist Id', type: 'string', value: 'musicbrainz_lyricistid' }, + { label: 'MusicBrainz Mixer Id', type: 'string', value: 'musicbrainz_mixerid' }, + { label: 'MusicBrainz Performer Id', type: 'string', value: 'musicbrainz_performerid' }, + { label: 'MusicBrainz Producer Id', type: 'string', value: 'musicbrainz_producerid' }, + { label: 'MusicBrainz Recording Id', type: 'string', value: 'mbz_recording_id' }, + { label: 'MusicBrainz Release Group Id', type: 'string', value: 'mbz_release_group_id' }, + { label: 'MusicBrainz Release Track Id', type: 'string', value: 'mbz_release_track_id' }, + { label: 'MusicBrainz Remixer Id', type: 'string', value: 'musicbrainz_remixerid' }, { label: 'MusicBrainz Track Id', type: 'string', value: 'musicbrainz_trackid' }, { label: 'MusicBrainz Work Id', type: 'string', value: 'musicbrainz_workid' }, { label: 'Name', type: 'string', value: 'title' }, @@ -157,11 +172,11 @@ export const NDSongQueryFields = [ { label: 'Sort Lyricist', type: 'string', value: 'lyricistsort' }, { label: 'Sort Name', type: 'string', value: 'titlesort' }, { label: 'Subtitle', type: 'string', value: 'subtitle' }, - { label: 'Track Number', type: 'number', value: 'track' }, + { label: 'Track Number', type: 'number', value: 'tracknumber' }, { label: 'Track Total', type: 'number', value: 'tracktotal' }, - { label: 'Year', type: 'number', value: 'year' }, { label: 'Website', type: 'string', value: 'website' }, { label: 'Work', type: 'string', value: 'work' }, + { label: 'Year', type: 'number', value: 'year' }, ]; export const NDSongQueryPlaylistOperators = [