mirror of
https://github.com/jeffvli/feishin.git
synced 2026-08-08 05:12:57 +02:00
reimplement smart playlists
This commit is contained in:
@@ -43,18 +43,29 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
|
||||
},
|
||||
});
|
||||
const [isSmartPlaylist, setIsSmartPlaylist] = useState(false);
|
||||
const [step, setStep] = useState<1 | 2>(1);
|
||||
|
||||
const handleSubmit = form.onSubmit((values) => {
|
||||
if (isSmartPlaylist) {
|
||||
values._custom!.navidrome = {
|
||||
...values._custom?.navidrome,
|
||||
rules: queryBuilderRef.current?.getFilters(),
|
||||
};
|
||||
if (!server) return;
|
||||
|
||||
// If creating a smart playlist and we're on the first step, advance to step 2
|
||||
// to configure the query instead of submitting immediately.
|
||||
if (isSmartPlaylist && step === 1) {
|
||||
setStep(2);
|
||||
return;
|
||||
}
|
||||
|
||||
const smartPlaylist = queryBuilderRef.current?.getFilters();
|
||||
|
||||
if (!server) return;
|
||||
const rules =
|
||||
isSmartPlaylist && smartPlaylist?.filters
|
||||
? {
|
||||
...convertQueryGroupToNDQuery(smartPlaylist.filters),
|
||||
limit: smartPlaylist.extraFilters.limit,
|
||||
order: smartPlaylist.extraFilters.sortOrder,
|
||||
sort: smartPlaylist.extraFilters.sortBy,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
mutation.mutate(
|
||||
{
|
||||
@@ -64,16 +75,10 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
|
||||
_custom: {
|
||||
navidrome: {
|
||||
...values._custom?.navidrome,
|
||||
rules:
|
||||
isSmartPlaylist && smartPlaylist?.filters
|
||||
? {
|
||||
...convertQueryGroupToNDQuery(smartPlaylist.filters),
|
||||
limit: smartPlaylist.extraFilters.limit,
|
||||
order: smartPlaylist.extraFilters.sortOrder,
|
||||
sort: smartPlaylist.extraFilters.sortBy,
|
||||
}
|
||||
: undefined,
|
||||
rules,
|
||||
},
|
||||
// Top-level rules field is what Navidrome expects for smart playlists.
|
||||
...(rules ? { rules } : {}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -100,51 +105,63 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Stack>
|
||||
<TextInput
|
||||
data-autofocus
|
||||
label={t('form.createPlaylist.input', {
|
||||
context: 'name',
|
||||
postProcess: 'titleCase',
|
||||
})}
|
||||
required
|
||||
{...form.getInputProps('name')}
|
||||
/>
|
||||
{server?.type === ServerType.NAVIDROME && (
|
||||
<Textarea
|
||||
autosize
|
||||
label={t('form.createPlaylist.input', {
|
||||
context: 'description',
|
||||
postProcess: 'titleCase',
|
||||
})}
|
||||
minRows={5}
|
||||
{...form.getInputProps('comment')}
|
||||
/>
|
||||
)}
|
||||
<Group>
|
||||
{isPublicDisplayed && (
|
||||
<Switch
|
||||
{step === 1 && (
|
||||
<>
|
||||
<TextInput
|
||||
data-autofocus
|
||||
label={t('form.createPlaylist.input', {
|
||||
context: 'public',
|
||||
context: 'name',
|
||||
postProcess: 'titleCase',
|
||||
})}
|
||||
{...form.getInputProps('public', {
|
||||
type: 'checkbox',
|
||||
})}
|
||||
required
|
||||
{...form.getInputProps('name')}
|
||||
/>
|
||||
)}
|
||||
{server?.type === ServerType.NAVIDROME &&
|
||||
hasFeature(server, ServerFeature.PLAYLISTS_SMART) && (
|
||||
<Switch
|
||||
label="Is smart playlist?"
|
||||
onChange={(e) => setIsSmartPlaylist(e.currentTarget.checked)}
|
||||
{server?.type === ServerType.NAVIDROME && (
|
||||
<Textarea
|
||||
autosize
|
||||
label={t('form.createPlaylist.input', {
|
||||
context: 'description',
|
||||
postProcess: 'titleCase',
|
||||
})}
|
||||
minRows={5}
|
||||
{...form.getInputProps('comment')}
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
{server?.type === ServerType.NAVIDROME && isSmartPlaylist && (
|
||||
<Group>
|
||||
{isPublicDisplayed && (
|
||||
<Switch
|
||||
label={t('form.createPlaylist.input', {
|
||||
context: 'public',
|
||||
postProcess: 'titleCase',
|
||||
})}
|
||||
{...form.getInputProps('public', {
|
||||
type: 'checkbox',
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{server?.type === ServerType.NAVIDROME &&
|
||||
hasFeature(server, ServerFeature.PLAYLISTS_SMART) && (
|
||||
<Switch
|
||||
checked={isSmartPlaylist}
|
||||
label="Is smart playlist?"
|
||||
onChange={(e) => {
|
||||
const next = e.currentTarget.checked;
|
||||
setIsSmartPlaylist(next);
|
||||
if (!next) {
|
||||
setStep(1);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isSmartPlaylist && step === 2 && (
|
||||
<Stack pt="1rem">
|
||||
<Text>Query Editor</Text>
|
||||
<PlaylistQueryBuilder
|
||||
isSaving={false}
|
||||
isSaving={mutation.isPending}
|
||||
limit={undefined}
|
||||
query={undefined}
|
||||
ref={queryBuilderRef}
|
||||
@@ -155,6 +172,11 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
|
||||
)}
|
||||
|
||||
<Group justify="flex-end">
|
||||
{isSmartPlaylist && step === 2 && (
|
||||
<ModalButton onClick={() => setStep(1)} px="2xl" uppercase variant="subtle">
|
||||
Back
|
||||
</ModalButton>
|
||||
)}
|
||||
<ModalButton onClick={onCancel} px="2xl" uppercase variant="subtle">
|
||||
{t('common.cancel')}
|
||||
</ModalButton>
|
||||
@@ -164,7 +186,9 @@ export const CreatePlaylistForm = ({ onCancel }: CreatePlaylistFormProps) => {
|
||||
type="submit"
|
||||
variant="filled"
|
||||
>
|
||||
{t('common.create')}
|
||||
{isSmartPlaylist && step === 1
|
||||
? t('common.confirm', { postProcess: 'sentenceCase' })
|
||||
: t('common.create')}
|
||||
</ModalButton>
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user