Add inPlaylist and notInPlaylist operators

This commit is contained in:
jeffvli 2024-05-02 21:35:23 -07:00 committed by Jeff
parent 7bfdbb5d92
commit 785f0ef77f
4 changed files with 46 additions and 10 deletions

View file

@ -400,6 +400,7 @@ export const NDSongQueryFields = [
{ label: 'File Type', type: 'string', value: 'filetype' }, { label: 'File Type', type: 'string', value: 'filetype' },
{ label: 'Genre', type: 'string', value: 'genre' }, { label: 'Genre', type: 'string', value: 'genre' },
{ label: 'Has CoverArt', type: 'boolean', value: 'hascoverart' }, { label: 'Has CoverArt', type: 'boolean', value: 'hascoverart' },
{ label: 'Playlist', type: 'playlist', value: 'id' },
{ label: 'Is Compilation', type: 'boolean', value: 'compilation' }, { label: 'Is Compilation', type: 'boolean', value: 'compilation' },
{ label: 'Is Favorite', type: 'boolean', value: 'loved' }, { label: 'Is Favorite', type: 'boolean', value: 'loved' },
{ label: 'Lyrics', type: 'string', value: 'lyrics' }, { label: 'Lyrics', type: 'string', value: 'lyrics' },
@ -415,6 +416,11 @@ export const NDSongQueryFields = [
{ label: 'Year', type: 'number', value: 'year' }, { label: 'Year', type: 'number', value: 'year' },
]; ];
export const NDSongQueryPlaylistOperators = [
{ label: 'is in', value: 'inPlaylist' },
{ label: 'is not in', value: 'notInPlaylist' },
];
export const NDSongQueryDateOperators = [ export const NDSongQueryDateOperators = [
{ label: 'is', value: 'is' }, { label: 'is', value: 'is' },
{ label: 'is not', value: 'isNot' }, { label: 'is not', value: 'isNot' },

View file

@ -54,8 +54,10 @@ interface QueryBuilderProps {
boolean: { label: string; value: string }[]; boolean: { label: string; value: string }[];
date: { label: string; value: string }[]; date: { label: string; value: string }[];
number: { label: string; value: string }[]; number: { label: string; value: string }[];
playlist: { label: string; value: string }[];
string: { label: string; value: string }[]; string: { label: string; value: string }[];
}; };
playlists?: { label: string; value: string }[];
uniqueId: string; uniqueId: string;
} }
@ -73,6 +75,7 @@ export const QueryBuilder = ({
onChangeValue, onChangeValue,
onClearFilters, onClearFilters,
onResetFilters, onResetFilters,
playlists,
groupIndex, groupIndex,
uniqueId, uniqueId,
filters, filters,
@ -180,6 +183,7 @@ export const QueryBuilder = ({
level={level} level={level}
noRemove={data?.rules?.length === 1} noRemove={data?.rules?.length === 1}
operators={operators} operators={operators}
selectData={playlists}
onChangeField={onChangeField} onChangeField={onChangeField}
onChangeOperator={onChangeOperator} onChangeOperator={onChangeOperator}
onChangeValue={onChangeValue} onChangeValue={onChangeValue}
@ -204,6 +208,7 @@ export const QueryBuilder = ({
groupIndex={[...(groupIndex || []), index]} groupIndex={[...(groupIndex || []), index]}
level={level + 1} level={level + 1}
operators={operators} operators={operators}
playlists={playlists}
uniqueId={group.uniqueId} uniqueId={group.uniqueId}
onAddRule={onAddRule} onAddRule={onAddRule}
onAddRuleGroup={onAddRuleGroup} onAddRuleGroup={onAddRuleGroup}

View file

@ -28,9 +28,10 @@ interface QueryOptionProps {
number: { label: string; value: string }[]; number: { label: string; value: string }[];
string: { label: string; value: string }[]; string: { label: string; value: string }[];
}; };
selectData?: { label: string; value: string }[];
} }
const QueryValueInput = ({ onChange, type, ...props }: any) => { const QueryValueInput = ({ onChange, type, data, ...props }: any) => {
const [numberRange, setNumberRange] = useState([0, 0]); const [numberRange, setNumberRange] = useState([0, 0]);
switch (type) { switch (type) {
@ -59,7 +60,6 @@ const QueryValueInput = ({ onChange, type, ...props }: any) => {
{...props} {...props}
/> />
); );
case 'dateRange': case 'dateRange':
return ( return (
<> <>
@ -87,7 +87,6 @@ const QueryValueInput = ({ onChange, type, ...props }: any) => {
/> />
</> </>
); );
case 'boolean': case 'boolean':
return ( return (
<Select <Select
@ -99,6 +98,14 @@ const QueryValueInput = ({ onChange, type, ...props }: any) => {
{...props} {...props}
/> />
); );
case 'playlist':
return (
<Select
data={data}
onChange={onChange}
{...props}
/>
);
default: default:
return <></>; return <></>;
@ -116,6 +123,7 @@ export const QueryBuilderOption = ({
onChangeField, onChangeField,
onChangeOperator, onChangeOperator,
onChangeValue, onChangeValue,
selectData,
}: QueryOptionProps) => { }: QueryOptionProps) => {
const { field, operator, uniqueId, value } = data; const { field, operator, uniqueId, value } = data;
@ -133,10 +141,7 @@ export const QueryBuilderOption = ({
const handleChangeValue = (e: any) => { const handleChangeValue = (e: any) => {
const isDirectValue = const isDirectValue =
typeof e === 'string' || typeof e === 'string' || typeof e === 'number' || typeof e === 'undefined';
typeof e === 'number' ||
typeof e === 'undefined' ||
typeof e === null;
if (isDirectValue) { if (isDirectValue) {
return onChangeValue({ return onChangeValue({
@ -207,6 +212,7 @@ export const QueryBuilderOption = ({
/> />
{field ? ( {field ? (
<QueryValueInput <QueryValueInput
data={selectData || []}
defaultValue={value} defaultValue={value}
maxWidth={170} maxWidth={170}
size="sm" size="sm"

View file

@ -1,4 +1,4 @@
import { forwardRef, Ref, useImperativeHandle, useState } from 'react'; import { forwardRef, Ref, useImperativeHandle, useMemo, useState } from 'react';
import { Group } from '@mantine/core'; import { Group } from '@mantine/core';
import { useForm } from '@mantine/form'; import { useForm } from '@mantine/form';
import clone from 'lodash/clone'; import clone from 'lodash/clone';
@ -21,14 +21,17 @@ import {
import { QueryBuilderGroup, QueryBuilderRule } from '/@/renderer/types'; import { QueryBuilderGroup, QueryBuilderRule } from '/@/renderer/types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { RiMore2Fill, RiSaveLine } from 'react-icons/ri'; import { RiMore2Fill, RiSaveLine } from 'react-icons/ri';
import { SongListSort } from '/@/renderer/api/types'; import { PlaylistListSort, SongListSort, SortOrder } from '/@/renderer/api/types';
import { import {
NDSongQueryBooleanOperators, NDSongQueryBooleanOperators,
NDSongQueryDateOperators, NDSongQueryDateOperators,
NDSongQueryFields, NDSongQueryFields,
NDSongQueryNumberOperators, NDSongQueryNumberOperators,
NDSongQueryPlaylistOperators,
NDSongQueryStringOperators, NDSongQueryStringOperators,
} from '/@/renderer/api/navidrome.types'; } from '/@/renderer/api/navidrome.types';
import { usePlaylistList } from '/@/renderer/features/playlists/queries/playlist-list-query';
import { useCurrentServer } from '/@/renderer/store';
type AddArgs = { type AddArgs = {
groupIndex: number[]; groupIndex: number[];
@ -88,10 +91,24 @@ export const PlaylistQueryBuilder = forwardRef(
ref: Ref<PlaylistQueryBuilderRef>, ref: Ref<PlaylistQueryBuilderRef>,
) => { ) => {
const { t } = useTranslation(); const { t } = useTranslation();
const server = useCurrentServer();
const [filters, setFilters] = useState<QueryBuilderGroup>( const [filters, setFilters] = useState<QueryBuilderGroup>(
query ? convertNDQueryToQueryGroup(query) : DEFAULT_QUERY, query ? convertNDQueryToQueryGroup(query) : DEFAULT_QUERY,
); );
const { data: playlists } = usePlaylistList({
query: { sortBy: PlaylistListSort.NAME, sortOrder: SortOrder.ASC, startIndex: 0 },
serverId: server?.id,
});
const playlistData = useMemo(() => {
if (!playlists) return [];
return playlists.items.map((p) => ({
label: p.name,
value: p.id,
}));
}, [playlists]);
const extraFiltersForm = useForm({ const extraFiltersForm = useForm({
initialValues: { initialValues: {
limit, limit,
@ -367,7 +384,7 @@ export const PlaylistQueryBuilder = forwardRef(
return ( return (
<MotionFlex <MotionFlex
direction="column" direction="column"
h="calc(100% - 2.5rem)" h="calc(100% - 3.5rem)"
justify="space-between" justify="space-between"
> >
<ScrollArea <ScrollArea
@ -383,8 +400,10 @@ export const PlaylistQueryBuilder = forwardRef(
boolean: NDSongQueryBooleanOperators, boolean: NDSongQueryBooleanOperators,
date: NDSongQueryDateOperators, date: NDSongQueryDateOperators,
number: NDSongQueryNumberOperators, number: NDSongQueryNumberOperators,
playlist: NDSongQueryPlaylistOperators,
string: NDSongQueryStringOperators, string: NDSongQueryStringOperators,
}} }}
playlists={playlistData}
uniqueId={filters.uniqueId} uniqueId={filters.uniqueId}
onAddRule={handleAddRule} onAddRule={handleAddRule}
onAddRuleGroup={handleAddRuleGroup} onAddRuleGroup={handleAddRuleGroup}