update fields and add multiselect to smart playlist sort

This commit is contained in:
jeffvli
2025-11-28 22:30:10 -08:00
parent 9b17d3513a
commit 72e2e6daca
5 changed files with 63 additions and 26 deletions
@@ -57,13 +57,18 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
const smartPlaylist = queryBuilderRef.current?.getFilters(); const smartPlaylist = queryBuilderRef.current?.getFilters();
const sortValue =
isSmartPlaylist && smartPlaylist?.extraFilters?.sortBy
? smartPlaylist.extraFilters.sortBy.join(',')
: undefined;
const rules = const rules =
isSmartPlaylist && smartPlaylist?.filters isSmartPlaylist && smartPlaylist?.filters
? { ? {
...convertQueryGroupToNDQuery(smartPlaylist.filters), ...convertQueryGroupToNDQuery(smartPlaylist.filters),
limit: smartPlaylist.extraFilters.limit, limit: smartPlaylist.extraFilters.limit,
order: smartPlaylist.extraFilters.sortOrder, order: smartPlaylist.extraFilters.sortOrder,
sort: smartPlaylist.extraFilters.sortBy, sort: sortValue || 'dateAdded',
} }
: undefined; : undefined;
@@ -165,7 +170,7 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
limit={undefined} limit={undefined}
query={undefined} query={undefined}
ref={queryBuilderRef} ref={queryBuilderRef}
sortBy={SongListSort.ALBUM} sortBy={[SongListSort.ALBUM]}
sortOrder="asc" sortOrder="asc"
/> />
</Stack> </Stack>
@@ -53,7 +53,7 @@ export const PlaylistDetailSongListHeader = ({
{formatDurationString(playlistDuration)} {formatDurationString(playlistDuration)}
</LibraryHeaderBar.Badge> </LibraryHeaderBar.Badge>
)} )}
<LibraryHeaderBar.Badge isLoading={!itemCount}> <LibraryHeaderBar.Badge isLoading={!!itemCount}>
{itemCount} {itemCount}
</LibraryHeaderBar.Badge> </LibraryHeaderBar.Badge>
</LibraryHeaderBar> </LibraryHeaderBar>
@@ -30,6 +30,7 @@ import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
import { Flex } from '/@/shared/components/flex/flex'; import { Flex } from '/@/shared/components/flex/flex';
import { Group } from '/@/shared/components/group/group'; import { Group } from '/@/shared/components/group/group';
import { Icon } from '/@/shared/components/icon/icon'; 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 { NumberInput } from '/@/shared/components/number-input/number-input';
import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area'; import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
import { Select } from '/@/shared/components/select/select'; import { Select } from '/@/shared/components/select/select';
@@ -52,15 +53,15 @@ interface PlaylistQueryBuilderProps {
limit?: number; limit?: number;
onSave?: ( onSave?: (
parsedFilter: any, parsedFilter: any,
extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, extraFilters: { limit?: number; sortBy?: string[]; sortOrder?: string },
) => void; ) => void;
onSaveAs?: ( onSaveAs?: (
parsedFilter: any, parsedFilter: any,
extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, extraFilters: { limit?: number; sortBy?: string[]; sortOrder?: string },
) => void; ) => void;
playlistId?: string; playlistId?: string;
query: any; query: any;
sortBy: SongListSort; sortBy: SongListSort | SongListSort[];
sortOrder: 'asc' | 'desc'; sortOrder: 'asc' | 'desc';
} }
@@ -82,7 +83,7 @@ export type PlaylistQueryBuilderRef = {
getFilters: () => { getFilters: () => {
extraFilters: { extraFilters: {
limit?: number; limit?: number;
sortBy?: string; sortBy?: string[];
sortOrder?: string; sortOrder?: string;
}; };
filters: QueryBuilderGroup; filters: QueryBuilderGroup;
@@ -133,7 +134,7 @@ export const PlaylistQueryBuilder = forwardRef(
const extraFiltersForm = useForm({ const extraFiltersForm = useForm({
initialValues: { initialValues: {
limit, limit,
sortBy, sortBy: Array.isArray(sortBy) ? sortBy : sortBy ? [sortBy] : [],
sortOrder, sortOrder,
}, },
}); });
@@ -442,13 +443,12 @@ export const PlaylistQueryBuilder = forwardRef(
/> />
</ScrollArea> </ScrollArea>
<Group align="flex-end" justify="space-between" m="1rem" wrap="nowrap"> <Group align="flex-end" justify="space-between" m="1rem" wrap="nowrap">
<Group gap="sm" w="100%" wrap="nowrap"> <Group align="flex-end" gap="sm" w="100%" wrap="nowrap">
<Select <MultiSelect
data={sortOptions} data={sortOptions}
label="Sort" label="Sort"
maxWidth="20%" maxWidth="50%"
searchable searchable
width={150}
{...extraFiltersForm.getInputProps('sortBy')} {...extraFiltersForm.getInputProps('sortBy')}
/> />
<Select <Select
@@ -41,15 +41,20 @@ const PlaylistDetailSongListRoute = () => {
const handleSave = ( const handleSave = (
filter: Record<string, any>, filter: Record<string, any>,
extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, extraFilters: { limit?: number; sortBy?: string[]; sortOrder?: string },
) => { ) => {
if (!detailQuery?.data) return; if (!detailQuery?.data) return;
const sortValue =
extraFilters.sortBy && extraFilters.sortBy.length > 0
? extraFilters.sortBy.join(',')
: 'dateAdded';
const rules = { const rules = {
...filter, ...filter,
limit: extraFilters.limit || undefined, limit: extraFilters.limit || undefined,
order: extraFilters.sortOrder || 'desc', order: extraFilters.sortOrder || 'desc',
sort: extraFilters.sortBy || 'dateAdded', sort: sortValue,
}; };
createPlaylistMutation.mutate( createPlaylistMutation.mutate(
@@ -89,15 +94,20 @@ const PlaylistDetailSongListRoute = () => {
const handleSaveAs = ( const handleSaveAs = (
filter: Record<string, any>, filter: Record<string, any>,
extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, extraFilters: { limit?: number; sortBy?: string[]; sortOrder?: string },
) => { ) => {
if (!detailQuery?.data) return; if (!detailQuery?.data) return;
const sortValue =
extraFilters.sortBy && extraFilters.sortBy.length > 0
? extraFilters.sortBy.join(',')
: 'dateAdded';
const rules = { const rules = {
...filter, ...filter,
limit: extraFilters.limit || undefined, limit: extraFilters.limit || undefined,
order: extraFilters.sortOrder || 'desc', order: extraFilters.sortOrder || 'desc',
sort: extraFilters.sortBy || 'dateAdded', sort: sortValue,
}; };
openModal({ openModal({
@@ -255,9 +265,16 @@ const PlaylistDetailSongListRoute = () => {
onSaveAs={handleSaveAs} onSaveAs={handleSaveAs}
playlistId={playlistId} playlistId={playlistId}
query={detailQuery?.data?.rules} query={detailQuery?.data?.rules}
sortBy={ sortBy={(() => {
detailQuery?.data?.rules?.sort || SongListSort.ALBUM 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'} sortOrder={detailQuery?.data?.rules?.order || 'asc'}
/> />
)} )}
+22 -7
View File
@@ -76,7 +76,9 @@ export const NDSongQueryFields = [
{ label: 'Arranger', type: 'string', value: 'arranger' }, { label: 'Arranger', type: 'string', value: 'arranger' },
{ label: 'Artist', type: 'string', value: 'artist' }, { label: 'Artist', type: 'string', value: 'artist' },
{ label: 'Artists', type: 'string', value: 'artists' }, { label: 'Artists', type: 'string', value: 'artists' },
{ label: 'ASIN', type: 'string', value: 'asin' },
{ label: 'Barcode', type: 'string', value: 'barcode' }, { label: 'Barcode', type: 'string', value: 'barcode' },
{ label: 'Bit Depth', type: 'number', value: 'bitdepth' },
{ label: 'Bitrate', type: 'number', value: 'bitrate' }, { label: 'Bitrate', type: 'number', value: 'bitrate' },
{ label: 'BPM', type: 'number', value: 'bpm' }, { label: 'BPM', type: 'number', value: 'bpm' },
{ label: 'Catalog Number', type: 'string', value: 'catalognumber' }, { label: 'Catalog Number', type: 'string', value: 'catalognumber' },
@@ -110,6 +112,7 @@ export const NDSongQueryFields = [
{ label: 'Key', type: 'string', value: 'key' }, { label: 'Key', type: 'string', value: 'key' },
{ label: 'Language', type: 'string', value: 'language' }, { label: 'Language', type: 'string', value: 'language' },
{ label: 'License', type: 'string', value: 'license' }, { label: 'License', type: 'string', value: 'license' },
{ label: 'Library Id', type: 'string', value: 'library_id' },
{ label: 'Lyricist', type: 'string', value: 'lyricist' }, { label: 'Lyricist', type: 'string', value: 'lyricist' },
{ label: 'Lyrics', type: 'string', value: 'lyrics' }, { label: 'Lyrics', type: 'string', value: 'lyrics' },
{ label: 'Media', type: 'string', value: 'media' }, { label: 'Media', type: 'string', value: 'media' },
@@ -118,12 +121,24 @@ export const NDSongQueryFields = [
{ label: 'Movement', type: 'string', value: 'movement' }, { label: 'Movement', type: 'string', value: 'movement' },
{ label: 'Movement Name', type: 'string', value: 'movementname' }, { label: 'Movement Name', type: 'string', value: 'movementname' },
{ label: 'Movement Total', type: 'number', value: 'movementtotal' }, { label: 'Movement Total', type: 'number', value: 'movementtotal' },
{ label: 'MusicBrainz Artist Id', type: 'string', value: 'musicbrainz_artistid' }, { label: 'MusicBrainz Album Artist Id', type: 'string', value: 'mbz_album_artist_id' },
{ label: 'MusicBrainz Album Artist Id', type: 'string', value: 'musicbrainz_albumartistid' }, { label: 'MusicBrainz Album Id', type: 'string', value: 'mbz_album_id' },
{ label: 'MusicBrainz Album Id', type: 'string', value: 'musicbrainz_albumid' }, { 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 Disc Id', type: 'string', value: 'musicbrainz_discid' },
{ label: 'MusicBrainz Recording Id', type: 'string', value: 'musicbrainz_recordingid' }, { label: 'MusicBrainz DJ Mixer Id', type: 'string', value: 'musicbrainz_djmixerid' },
{ label: 'MusicBrainz Release Group Id', type: 'string', value: 'musicbrainz_releasegroupid' }, { 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 Track Id', type: 'string', value: 'musicbrainz_trackid' },
{ label: 'MusicBrainz Work Id', type: 'string', value: 'musicbrainz_workid' }, { label: 'MusicBrainz Work Id', type: 'string', value: 'musicbrainz_workid' },
{ label: 'Name', type: 'string', value: 'title' }, { label: 'Name', type: 'string', value: 'title' },
@@ -157,11 +172,11 @@ export const NDSongQueryFields = [
{ label: 'Sort Lyricist', type: 'string', value: 'lyricistsort' }, { label: 'Sort Lyricist', type: 'string', value: 'lyricistsort' },
{ label: 'Sort Name', type: 'string', value: 'titlesort' }, { label: 'Sort Name', type: 'string', value: 'titlesort' },
{ label: 'Subtitle', type: 'string', value: 'subtitle' }, { 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: 'Track Total', type: 'number', value: 'tracktotal' },
{ label: 'Year', type: 'number', value: 'year' },
{ label: 'Website', type: 'string', value: 'website' }, { label: 'Website', type: 'string', value: 'website' },
{ label: 'Work', type: 'string', value: 'work' }, { label: 'Work', type: 'string', value: 'work' },
{ label: 'Year', type: 'number', value: 'year' },
]; ];
export const NDSongQueryPlaylistOperators = [ export const NDSongQueryPlaylistOperators = [