Forward playlist query filters
This commit is contained in:
parent
9a809a61dd
commit
e5f478218e
1 changed files with 361 additions and 337 deletions
|
@ -1,4 +1,4 @@
|
||||||
import { useState } from 'react';
|
import { forwardRef, Ref, useImperativeHandle, 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';
|
||||||
|
@ -20,7 +20,7 @@ import {
|
||||||
} from '/@/renderer/features/playlists/utils';
|
} from '/@/renderer/features/playlists/utils';
|
||||||
import { QueryBuilderGroup, QueryBuilderRule } from '/@/renderer/types';
|
import { QueryBuilderGroup, QueryBuilderRule } from '/@/renderer/types';
|
||||||
import { RiMore2Fill, RiSaveLine } from 'react-icons/ri';
|
import { RiMore2Fill, RiSaveLine } from 'react-icons/ri';
|
||||||
import { SongListSort, SortOrder } from '/@/renderer/api/types';
|
import { SongListSort } from '/@/renderer/api/types';
|
||||||
import {
|
import {
|
||||||
NDSongQueryBooleanOperators,
|
NDSongQueryBooleanOperators,
|
||||||
NDSongQueryDateOperators,
|
NDSongQueryDateOperators,
|
||||||
|
@ -43,17 +43,17 @@ type DeleteArgs = {
|
||||||
interface PlaylistQueryBuilderProps {
|
interface PlaylistQueryBuilderProps {
|
||||||
isSaving?: boolean;
|
isSaving?: boolean;
|
||||||
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;
|
||||||
query: any;
|
query: any;
|
||||||
sortBy: SongListSort;
|
sortBy: SongListSort;
|
||||||
sortOrder: SortOrder;
|
sortOrder: 'asc' | 'desc';
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_QUERY = {
|
const DEFAULT_QUERY = {
|
||||||
|
@ -70,381 +70,405 @@ const DEFAULT_QUERY = {
|
||||||
uniqueId: nanoid(),
|
uniqueId: nanoid(),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PlaylistQueryBuilder = ({
|
export type PlaylistQueryBuilderRef = {
|
||||||
sortOrder,
|
getFilters: () => {
|
||||||
sortBy,
|
extraFilters: {
|
||||||
limit,
|
limit?: number;
|
||||||
isSaving,
|
sortBy?: string;
|
||||||
query,
|
sortOrder?: string;
|
||||||
onSave,
|
};
|
||||||
onSaveAs,
|
filters: QueryBuilderGroup;
|
||||||
}: PlaylistQueryBuilderProps) => {
|
};
|
||||||
const [filters, setFilters] = useState<QueryBuilderGroup>(
|
};
|
||||||
query ? convertNDQueryToQueryGroup(query) : DEFAULT_QUERY,
|
|
||||||
);
|
|
||||||
|
|
||||||
const extraFiltersForm = useForm({
|
export const PlaylistQueryBuilder = forwardRef(
|
||||||
initialValues: {
|
(
|
||||||
limit,
|
{ sortOrder, sortBy, limit, isSaving, query, onSave, onSaveAs }: PlaylistQueryBuilderProps,
|
||||||
sortBy,
|
ref: Ref<PlaylistQueryBuilderRef>,
|
||||||
sortOrder,
|
) => {
|
||||||
},
|
const [filters, setFilters] = useState<QueryBuilderGroup>(
|
||||||
});
|
query ? convertNDQueryToQueryGroup(query) : DEFAULT_QUERY,
|
||||||
|
);
|
||||||
|
|
||||||
const handleResetFilters = () => {
|
const extraFiltersForm = useForm({
|
||||||
if (query) {
|
initialValues: {
|
||||||
setFilters(convertNDQueryToQueryGroup(query));
|
limit,
|
||||||
} else {
|
sortBy,
|
||||||
|
sortOrder,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
getFilters: () => ({
|
||||||
|
extraFilters: extraFiltersForm.values,
|
||||||
|
filters,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const handleResetFilters = () => {
|
||||||
|
if (query) {
|
||||||
|
setFilters(convertNDQueryToQueryGroup(query));
|
||||||
|
} else {
|
||||||
|
setFilters(DEFAULT_QUERY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClearFilters = () => {
|
||||||
setFilters(DEFAULT_QUERY);
|
setFilters(DEFAULT_QUERY);
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const handleClearFilters = () => {
|
const setFilterHandler = (newFilters: QueryBuilderGroup) => {
|
||||||
setFilters(DEFAULT_QUERY);
|
setFilters(newFilters);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setFilterHandler = (newFilters: QueryBuilderGroup) => {
|
const handleSave = () => {
|
||||||
setFilters(newFilters);
|
onSave?.(convertQueryGroupToNDQuery(filters), extraFiltersForm.values);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSaveAs = () => {
|
||||||
onSave(convertQueryGroupToNDQuery(filters), extraFiltersForm.values);
|
onSaveAs?.(convertQueryGroupToNDQuery(filters), extraFiltersForm.values);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveAs = () => {
|
const handleAddRuleGroup = (args: AddArgs) => {
|
||||||
onSaveAs(convertQueryGroupToNDQuery(filters), extraFiltersForm.values);
|
const { level, groupIndex } = args;
|
||||||
};
|
const filtersCopy = clone(filters);
|
||||||
|
|
||||||
const handleAddRuleGroup = (args: AddArgs) => {
|
const getPath = (level: number) => {
|
||||||
const { level, groupIndex } = args;
|
if (level === 0) return 'group';
|
||||||
const filtersCopy = clone(filters);
|
|
||||||
|
|
||||||
const getPath = (level: number) => {
|
const str = [];
|
||||||
if (level === 0) return 'group';
|
for (const index of groupIndex) {
|
||||||
|
str.push(`group[${index}]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${str.join('.')}.group`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const path = getPath(level);
|
||||||
|
const updatedFilters = setWith(
|
||||||
|
filtersCopy,
|
||||||
|
path,
|
||||||
|
[
|
||||||
|
...get(filtersCopy, path),
|
||||||
|
{
|
||||||
|
group: [],
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
field: '',
|
||||||
|
operator: '',
|
||||||
|
uniqueId: nanoid(),
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: 'any',
|
||||||
|
uniqueId: nanoid(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
clone,
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilterHandler(updatedFilters);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteRuleGroup = (args: DeleteArgs) => {
|
||||||
|
const { uniqueId, level, groupIndex } = args;
|
||||||
|
const filtersCopy = clone(filters);
|
||||||
|
|
||||||
|
const getPath = (level: number) => {
|
||||||
|
if (level === 0) return 'group';
|
||||||
|
|
||||||
|
const str = [];
|
||||||
|
for (let i = 0; i < groupIndex.length; i += 1) {
|
||||||
|
if (i !== groupIndex.length - 1) {
|
||||||
|
str.push(`group[${groupIndex[i]}]`);
|
||||||
|
} else {
|
||||||
|
str.push(`group`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${str.join('.')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const path = getPath(level);
|
||||||
|
|
||||||
|
const updatedFilters = setWith(
|
||||||
|
filtersCopy,
|
||||||
|
path,
|
||||||
|
[
|
||||||
|
...get(filtersCopy, path).filter(
|
||||||
|
(group: QueryBuilderGroup) => group.uniqueId !== uniqueId,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
clone,
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilterHandler(updatedFilters);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRulePath = (level: number, groupIndex: number[]) => {
|
||||||
|
if (level === 0) return 'rules';
|
||||||
|
|
||||||
const str = [];
|
const str = [];
|
||||||
for (const index of groupIndex) {
|
for (const index of groupIndex) {
|
||||||
str.push(`group[${index}]`);
|
str.push(`group[${index}]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${str.join('.')}.group`;
|
return `${str.join('.')}.rules`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const path = getPath(level);
|
const handleAddRule = (args: AddArgs) => {
|
||||||
const updatedFilters = setWith(
|
const { level, groupIndex } = args;
|
||||||
filtersCopy,
|
const filtersCopy = clone(filters);
|
||||||
path,
|
|
||||||
[
|
|
||||||
...get(filtersCopy, path),
|
|
||||||
{
|
|
||||||
group: [],
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
field: '',
|
|
||||||
operator: '',
|
|
||||||
uniqueId: nanoid(),
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: 'any',
|
|
||||||
uniqueId: nanoid(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
clone,
|
|
||||||
);
|
|
||||||
|
|
||||||
setFilterHandler(updatedFilters);
|
const path = getRulePath(level, groupIndex);
|
||||||
};
|
const updatedFilters = setWith(
|
||||||
|
filtersCopy,
|
||||||
|
path,
|
||||||
|
[
|
||||||
|
...get(filtersCopy, path),
|
||||||
|
{
|
||||||
|
field: '',
|
||||||
|
operator: '',
|
||||||
|
uniqueId: nanoid(),
|
||||||
|
value: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
clone,
|
||||||
|
);
|
||||||
|
|
||||||
const handleDeleteRuleGroup = (args: DeleteArgs) => {
|
setFilterHandler(updatedFilters);
|
||||||
const { uniqueId, level, groupIndex } = args;
|
};
|
||||||
const filtersCopy = clone(filters);
|
|
||||||
|
|
||||||
const getPath = (level: number) => {
|
const handleDeleteRule = (args: DeleteArgs) => {
|
||||||
if (level === 0) return 'group';
|
const { uniqueId, level, groupIndex } = args;
|
||||||
|
const filtersCopy = clone(filters);
|
||||||
|
|
||||||
const str = [];
|
const path = getRulePath(level, groupIndex);
|
||||||
for (let i = 0; i < groupIndex.length; i += 1) {
|
const updatedFilters = setWith(
|
||||||
if (i !== groupIndex.length - 1) {
|
filtersCopy,
|
||||||
|
path,
|
||||||
|
get(filtersCopy, path).filter((rule: QueryBuilderRule) => rule.uniqueId !== uniqueId),
|
||||||
|
clone,
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilterHandler(updatedFilters);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeField = (args: any) => {
|
||||||
|
const { uniqueId, level, groupIndex, value } = args;
|
||||||
|
const filtersCopy = clone(filters);
|
||||||
|
|
||||||
|
const path = getRulePath(level, groupIndex);
|
||||||
|
const updatedFilters = setWith(
|
||||||
|
filtersCopy,
|
||||||
|
path,
|
||||||
|
get(filtersCopy, path).map((rule: QueryBuilderGroup) => {
|
||||||
|
if (rule.uniqueId !== uniqueId) return rule;
|
||||||
|
return {
|
||||||
|
...rule,
|
||||||
|
field: value,
|
||||||
|
operator: '',
|
||||||
|
value: '',
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
clone,
|
||||||
|
);
|
||||||
|
|
||||||
|
setFilterHandler(updatedFilters);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeType = (args: any) => {
|
||||||
|
const { level, groupIndex, value } = args;
|
||||||
|
|
||||||
|
const filtersCopy = clone(filters);
|
||||||
|
|
||||||
|
if (level === 0) {
|
||||||
|
return setFilterHandler({ ...filtersCopy, type: value });
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTypePath = () => {
|
||||||
|
const str = [];
|
||||||
|
for (let i = 0; i < groupIndex.length; i += 1) {
|
||||||
str.push(`group[${groupIndex[i]}]`);
|
str.push(`group[${groupIndex[i]}]`);
|
||||||
} else {
|
|
||||||
str.push(`group`);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return `${str.join('.')}`;
|
return `${str.join('.')}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const path = getPath(level);
|
const path = getTypePath();
|
||||||
|
const updatedFilters = setWith(
|
||||||
const updatedFilters = setWith(
|
filtersCopy,
|
||||||
filtersCopy,
|
path,
|
||||||
path,
|
|
||||||
[...get(filtersCopy, path).filter((group: QueryBuilderGroup) => group.uniqueId !== uniqueId)],
|
|
||||||
clone,
|
|
||||||
);
|
|
||||||
|
|
||||||
setFilterHandler(updatedFilters);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRulePath = (level: number, groupIndex: number[]) => {
|
|
||||||
if (level === 0) return 'rules';
|
|
||||||
|
|
||||||
const str = [];
|
|
||||||
for (const index of groupIndex) {
|
|
||||||
str.push(`group[${index}]`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${str.join('.')}.rules`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAddRule = (args: AddArgs) => {
|
|
||||||
const { level, groupIndex } = args;
|
|
||||||
const filtersCopy = clone(filters);
|
|
||||||
|
|
||||||
const path = getRulePath(level, groupIndex);
|
|
||||||
const updatedFilters = setWith(
|
|
||||||
filtersCopy,
|
|
||||||
path,
|
|
||||||
[
|
|
||||||
...get(filtersCopy, path),
|
|
||||||
{
|
{
|
||||||
field: '',
|
...get(filtersCopy, path),
|
||||||
operator: '',
|
type: value,
|
||||||
uniqueId: nanoid(),
|
|
||||||
value: null,
|
|
||||||
},
|
},
|
||||||
],
|
clone,
|
||||||
clone,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
setFilterHandler(updatedFilters);
|
return setFilterHandler(updatedFilters);
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteRule = (args: DeleteArgs) => {
|
|
||||||
const { uniqueId, level, groupIndex } = args;
|
|
||||||
const filtersCopy = clone(filters);
|
|
||||||
|
|
||||||
const path = getRulePath(level, groupIndex);
|
|
||||||
const updatedFilters = setWith(
|
|
||||||
filtersCopy,
|
|
||||||
path,
|
|
||||||
get(filtersCopy, path).filter((rule: QueryBuilderRule) => rule.uniqueId !== uniqueId),
|
|
||||||
clone,
|
|
||||||
);
|
|
||||||
|
|
||||||
setFilterHandler(updatedFilters);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangeField = (args: any) => {
|
|
||||||
const { uniqueId, level, groupIndex, value } = args;
|
|
||||||
const filtersCopy = clone(filters);
|
|
||||||
|
|
||||||
const path = getRulePath(level, groupIndex);
|
|
||||||
const updatedFilters = setWith(
|
|
||||||
filtersCopy,
|
|
||||||
path,
|
|
||||||
get(filtersCopy, path).map((rule: QueryBuilderGroup) => {
|
|
||||||
if (rule.uniqueId !== uniqueId) return rule;
|
|
||||||
return {
|
|
||||||
...rule,
|
|
||||||
field: value,
|
|
||||||
operator: '',
|
|
||||||
value: '',
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
clone,
|
|
||||||
);
|
|
||||||
|
|
||||||
setFilterHandler(updatedFilters);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangeType = (args: any) => {
|
|
||||||
const { level, groupIndex, value } = args;
|
|
||||||
|
|
||||||
const filtersCopy = clone(filters);
|
|
||||||
|
|
||||||
if (level === 0) {
|
|
||||||
return setFilterHandler({ ...filtersCopy, type: value });
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTypePath = () => {
|
|
||||||
const str = [];
|
|
||||||
for (let i = 0; i < groupIndex.length; i += 1) {
|
|
||||||
str.push(`group[${groupIndex[i]}]`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${str.join('.')}`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const path = getTypePath();
|
const handleChangeOperator = (args: any) => {
|
||||||
const updatedFilters = setWith(
|
const { uniqueId, level, groupIndex, value } = args;
|
||||||
filtersCopy,
|
const filtersCopy = clone(filters);
|
||||||
path,
|
|
||||||
{
|
|
||||||
...get(filtersCopy, path),
|
|
||||||
type: value,
|
|
||||||
},
|
|
||||||
clone,
|
|
||||||
);
|
|
||||||
|
|
||||||
return setFilterHandler(updatedFilters);
|
const path = getRulePath(level, groupIndex);
|
||||||
};
|
const updatedFilters = setWith(
|
||||||
|
filtersCopy,
|
||||||
|
path,
|
||||||
|
get(filtersCopy, path).map((rule: QueryBuilderRule) => {
|
||||||
|
if (rule.uniqueId !== uniqueId) return rule;
|
||||||
|
return {
|
||||||
|
...rule,
|
||||||
|
operator: value,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
clone,
|
||||||
|
);
|
||||||
|
|
||||||
const handleChangeOperator = (args: any) => {
|
setFilterHandler(updatedFilters);
|
||||||
const { uniqueId, level, groupIndex, value } = args;
|
};
|
||||||
const filtersCopy = clone(filters);
|
|
||||||
|
|
||||||
const path = getRulePath(level, groupIndex);
|
const handleChangeValue = (args: any) => {
|
||||||
const updatedFilters = setWith(
|
const { uniqueId, level, groupIndex, value } = args;
|
||||||
filtersCopy,
|
const filtersCopy = clone(filters);
|
||||||
path,
|
|
||||||
get(filtersCopy, path).map((rule: QueryBuilderRule) => {
|
|
||||||
if (rule.uniqueId !== uniqueId) return rule;
|
|
||||||
return {
|
|
||||||
...rule,
|
|
||||||
operator: value,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
clone,
|
|
||||||
);
|
|
||||||
|
|
||||||
setFilterHandler(updatedFilters);
|
const path = getRulePath(level, groupIndex);
|
||||||
};
|
const updatedFilters = setWith(
|
||||||
|
filtersCopy,
|
||||||
|
path,
|
||||||
|
get(filtersCopy, path).map((rule: QueryBuilderRule) => {
|
||||||
|
if (rule.uniqueId !== uniqueId) return rule;
|
||||||
|
return {
|
||||||
|
...rule,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
clone,
|
||||||
|
);
|
||||||
|
|
||||||
const handleChangeValue = (args: any) => {
|
setFilterHandler(updatedFilters);
|
||||||
const { uniqueId, level, groupIndex, value } = args;
|
};
|
||||||
const filtersCopy = clone(filters);
|
|
||||||
|
|
||||||
const path = getRulePath(level, groupIndex);
|
const sortOptions = [
|
||||||
const updatedFilters = setWith(
|
{ label: 'Random', type: 'string', value: 'random' },
|
||||||
filtersCopy,
|
...NDSongQueryFields,
|
||||||
path,
|
];
|
||||||
get(filtersCopy, path).map((rule: QueryBuilderRule) => {
|
|
||||||
if (rule.uniqueId !== uniqueId) return rule;
|
|
||||||
return {
|
|
||||||
...rule,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
clone,
|
|
||||||
);
|
|
||||||
|
|
||||||
setFilterHandler(updatedFilters);
|
return (
|
||||||
};
|
<MotionFlex
|
||||||
|
direction="column"
|
||||||
const sortOptions = [{ label: 'Random', type: 'string', value: 'random' }, ...NDSongQueryFields];
|
h="calc(100% - 3rem)"
|
||||||
|
justify="space-between"
|
||||||
return (
|
|
||||||
<MotionFlex
|
|
||||||
direction="column"
|
|
||||||
h="calc(100% - 3rem)"
|
|
||||||
justify="space-between"
|
|
||||||
>
|
|
||||||
<ScrollArea
|
|
||||||
h="100%"
|
|
||||||
p="1rem"
|
|
||||||
>
|
|
||||||
<QueryBuilder
|
|
||||||
data={filters}
|
|
||||||
filters={NDSongQueryFields}
|
|
||||||
groupIndex={[]}
|
|
||||||
level={0}
|
|
||||||
operators={{
|
|
||||||
boolean: NDSongQueryBooleanOperators,
|
|
||||||
date: NDSongQueryDateOperators,
|
|
||||||
number: NDSongQueryNumberOperators,
|
|
||||||
string: NDSongQueryStringOperators,
|
|
||||||
}}
|
|
||||||
uniqueId={filters.uniqueId}
|
|
||||||
onAddRule={handleAddRule}
|
|
||||||
onAddRuleGroup={handleAddRuleGroup}
|
|
||||||
onChangeField={handleChangeField}
|
|
||||||
onChangeOperator={handleChangeOperator}
|
|
||||||
onChangeType={handleChangeType}
|
|
||||||
onChangeValue={handleChangeValue}
|
|
||||||
onClearFilters={handleClearFilters}
|
|
||||||
onDeleteRule={handleDeleteRule}
|
|
||||||
onDeleteRuleGroup={handleDeleteRuleGroup}
|
|
||||||
onResetFilters={handleResetFilters}
|
|
||||||
/>
|
|
||||||
</ScrollArea>
|
|
||||||
<Group
|
|
||||||
noWrap
|
|
||||||
align="flex-end"
|
|
||||||
p="1rem"
|
|
||||||
position="apart"
|
|
||||||
>
|
>
|
||||||
|
<ScrollArea
|
||||||
|
h="100%"
|
||||||
|
p="1rem"
|
||||||
|
>
|
||||||
|
<QueryBuilder
|
||||||
|
data={filters}
|
||||||
|
filters={NDSongQueryFields}
|
||||||
|
groupIndex={[]}
|
||||||
|
level={0}
|
||||||
|
operators={{
|
||||||
|
boolean: NDSongQueryBooleanOperators,
|
||||||
|
date: NDSongQueryDateOperators,
|
||||||
|
number: NDSongQueryNumberOperators,
|
||||||
|
string: NDSongQueryStringOperators,
|
||||||
|
}}
|
||||||
|
uniqueId={filters.uniqueId}
|
||||||
|
onAddRule={handleAddRule}
|
||||||
|
onAddRuleGroup={handleAddRuleGroup}
|
||||||
|
onChangeField={handleChangeField}
|
||||||
|
onChangeOperator={handleChangeOperator}
|
||||||
|
onChangeType={handleChangeType}
|
||||||
|
onChangeValue={handleChangeValue}
|
||||||
|
onClearFilters={handleClearFilters}
|
||||||
|
onDeleteRule={handleDeleteRule}
|
||||||
|
onDeleteRuleGroup={handleDeleteRuleGroup}
|
||||||
|
onResetFilters={handleResetFilters}
|
||||||
|
/>
|
||||||
|
</ScrollArea>
|
||||||
<Group
|
<Group
|
||||||
noWrap
|
noWrap
|
||||||
w="100%"
|
align="flex-end"
|
||||||
|
p="1rem"
|
||||||
|
position="apart"
|
||||||
>
|
>
|
||||||
<Select
|
<Group
|
||||||
searchable
|
noWrap
|
||||||
data={sortOptions}
|
w="100%"
|
||||||
label="Sort"
|
|
||||||
maxWidth="20%"
|
|
||||||
width={125}
|
|
||||||
{...extraFiltersForm.getInputProps('sortBy')}
|
|
||||||
/>
|
|
||||||
<Select
|
|
||||||
data={[
|
|
||||||
{
|
|
||||||
label: 'Ascending',
|
|
||||||
value: 'asc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Descending',
|
|
||||||
value: 'desc',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
label="Order"
|
|
||||||
maxWidth="20%"
|
|
||||||
width={125}
|
|
||||||
{...extraFiltersForm.getInputProps('sortOrder')}
|
|
||||||
/>
|
|
||||||
<NumberInput
|
|
||||||
label="Limit"
|
|
||||||
maxWidth="20%"
|
|
||||||
width={75}
|
|
||||||
{...extraFiltersForm.getInputProps('limit')}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
<Group noWrap>
|
|
||||||
<Button
|
|
||||||
loading={isSaving}
|
|
||||||
variant="filled"
|
|
||||||
onClick={handleSaveAs}
|
|
||||||
>
|
>
|
||||||
Save as
|
<Select
|
||||||
</Button>
|
searchable
|
||||||
<DropdownMenu position="bottom-end">
|
data={sortOptions}
|
||||||
<DropdownMenu.Target>
|
label="Sort"
|
||||||
|
maxWidth="20%"
|
||||||
|
width={125}
|
||||||
|
{...extraFiltersForm.getInputProps('sortBy')}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
data={[
|
||||||
|
{
|
||||||
|
label: 'Ascending',
|
||||||
|
value: 'asc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Descending',
|
||||||
|
value: 'desc',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
label="Order"
|
||||||
|
maxWidth="20%"
|
||||||
|
width={125}
|
||||||
|
{...extraFiltersForm.getInputProps('sortOrder')}
|
||||||
|
/>
|
||||||
|
<NumberInput
|
||||||
|
label="Limit"
|
||||||
|
maxWidth="20%"
|
||||||
|
width={75}
|
||||||
|
{...extraFiltersForm.getInputProps('limit')}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
{onSave && onSaveAs && (
|
||||||
|
<Group noWrap>
|
||||||
<Button
|
<Button
|
||||||
disabled={isSaving}
|
loading={isSaving}
|
||||||
p="0.5em"
|
variant="filled"
|
||||||
variant="default"
|
onClick={handleSaveAs}
|
||||||
>
|
>
|
||||||
<RiMore2Fill size={15} />
|
Save as
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenu.Target>
|
<DropdownMenu position="bottom-end">
|
||||||
<DropdownMenu.Dropdown>
|
<DropdownMenu.Target>
|
||||||
<DropdownMenu.Item
|
<Button
|
||||||
$danger
|
disabled={isSaving}
|
||||||
rightSection={
|
p="0.5em"
|
||||||
<RiSaveLine
|
variant="default"
|
||||||
color="var(--danger-color)"
|
>
|
||||||
size={15}
|
<RiMore2Fill size={15} />
|
||||||
/>
|
</Button>
|
||||||
}
|
</DropdownMenu.Target>
|
||||||
onClick={handleSave}
|
<DropdownMenu.Dropdown>
|
||||||
>
|
<DropdownMenu.Item
|
||||||
Save and replace
|
$danger
|
||||||
</DropdownMenu.Item>
|
rightSection={
|
||||||
</DropdownMenu.Dropdown>
|
<RiSaveLine
|
||||||
</DropdownMenu>
|
color="var(--danger-color)"
|
||||||
|
size={15}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={handleSave}
|
||||||
|
>
|
||||||
|
Save and replace
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Dropdown>
|
||||||
|
</DropdownMenu>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</MotionFlex>
|
||||||
</MotionFlex>
|
);
|
||||||
);
|
},
|
||||||
};
|
);
|
||||||
|
|
Reference in a new issue