You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
6.6 KiB
198 lines
6.6 KiB
import React, { useState, useEffect } from 'react'; |
|
|
|
import { Query, toApiQuery, QueryOrdering, TypesIncluded, QueryKeys, OrderKey } from '../types/Query'; |
|
import FilterControl from './FilterControl'; |
|
import * as serverApi from '../api'; |
|
import BrowseWindow, { Item } from './BrowseWindow'; |
|
import { FormControl, FormLabel, FormGroup, FormControlLabel, Checkbox, Select, MenuItem } from '@material-ui/core'; |
|
|
|
const _ = require('lodash'); |
|
|
|
interface ItemTypeCheckboxesProps { |
|
types: TypesIncluded, |
|
onChange: (types: TypesIncluded) => void; |
|
} |
|
|
|
function ItemTypeCheckboxes(props: ItemTypeCheckboxesProps) { |
|
const songChange = (v: any) => { |
|
props.onChange({ |
|
[QueryKeys.Songs]: v.target.checked, |
|
[QueryKeys.Artists]: props.types[QueryKeys.Artists], |
|
[QueryKeys.Tags]: props.types[QueryKeys.Tags] |
|
}); |
|
} |
|
const artistChange = (v: any) => { |
|
props.onChange({ |
|
[QueryKeys.Songs]: props.types[QueryKeys.Songs], |
|
[QueryKeys.Artists]: v.target.checked, |
|
[QueryKeys.Tags]: props.types[QueryKeys.Tags] |
|
}); |
|
} |
|
const tagChange = (v: any) => { |
|
props.onChange({ |
|
[QueryKeys.Songs]: props.types[QueryKeys.Songs], |
|
[QueryKeys.Artists]: props.types[QueryKeys.Artists], |
|
[QueryKeys.Tags]: v.target.checked |
|
}); |
|
} |
|
|
|
return <FormControl component='fieldset'> |
|
<FormLabel component='legend'>Result types</FormLabel> |
|
<FormGroup> |
|
<FormControlLabel |
|
control={<Checkbox checked={props.types[QueryKeys.Songs]} onChange={songChange} name='Songs' />} |
|
label="Songs" |
|
/> |
|
<FormControlLabel |
|
control={<Checkbox checked={props.types[QueryKeys.Artists]} onChange={artistChange} name='Artists' />} |
|
label="Artists" |
|
/> |
|
<FormControlLabel |
|
control={<Checkbox checked={props.types[QueryKeys.Tags]} onChange={tagChange} name='Tags' />} |
|
label="Tags" |
|
/> |
|
</FormGroup> |
|
</FormControl>; |
|
} |
|
|
|
interface OrderingWidgetProps { |
|
ordering: QueryOrdering, |
|
onChange: (o: QueryOrdering) => void; |
|
} |
|
|
|
function OrderingWidget(props: OrderingWidgetProps) { |
|
const onTypeChange = (e: any) => { |
|
props.onChange({ |
|
[QueryKeys.OrderBy]: { |
|
[QueryKeys.OrderKey]: e.target.value, |
|
}, |
|
[QueryKeys.Ascending]: props.ordering[QueryKeys.Ascending], |
|
}); |
|
} |
|
const onAscendingChange = (e: any) => { |
|
props.onChange({ |
|
[QueryKeys.OrderBy]: props.ordering[QueryKeys.OrderBy], |
|
[QueryKeys.Ascending]: (e.target.value == 'asc'), |
|
}); |
|
} |
|
|
|
return <FormControl component='fieldset'> |
|
<FormLabel component='legend'>Ordering</FormLabel> |
|
<FormGroup> |
|
<Select |
|
onChange={onTypeChange} |
|
value={props.ordering[QueryKeys.OrderBy][QueryKeys.OrderKey]} |
|
> |
|
<MenuItem value={OrderKey.Name}>Name</MenuItem> |
|
</Select> |
|
<Select |
|
onChange={onAscendingChange} |
|
value={props.ordering[QueryKeys.Ascending] ? 'asc' : 'desc'} |
|
> |
|
<MenuItem value={'asc'}>Ascending</MenuItem> |
|
<MenuItem value={'desc'}>Descending</MenuItem> |
|
</Select> |
|
</FormGroup> |
|
</FormControl>; |
|
} |
|
|
|
function toServerOrdering(o: QueryOrdering | undefined): serverApi.Ordering { |
|
if (!o) { |
|
return { |
|
orderBy: { |
|
type: serverApi.OrderByType.Name |
|
}, |
|
ascending: true |
|
}; |
|
} |
|
|
|
const keys = { |
|
[OrderKey.Name]: serverApi.OrderByType.Name, |
|
}; |
|
|
|
return { |
|
orderBy: { |
|
type: keys[o[QueryKeys.OrderBy][QueryKeys.OrderKey]] |
|
}, |
|
ascending: o[QueryKeys.Ascending], |
|
} |
|
} |
|
|
|
export interface IProps { |
|
query: Query | undefined, |
|
typesIncluded: TypesIncluded | undefined, |
|
resultOrder: QueryOrdering | undefined, |
|
onQueryChange: (q: Query) => void, |
|
onTypesChange: (t: TypesIncluded) => void, |
|
onOrderChange: (o: QueryOrdering) => void, |
|
} |
|
|
|
export default function QueryBrowseWindow(props: IProps) { |
|
const [songs, setSongs] = useState<serverApi.SongDetails[]>([]); |
|
const [artists, setArtists] = useState<serverApi.ArtistDetails[]>([]); |
|
//const [tags, setTags] = useState<serverApi.TagDetails[]>([]); |
|
|
|
var items: Item[] = []; |
|
props.typesIncluded && props.typesIncluded[QueryKeys.Songs] && items.push(...songs); |
|
props.typesIncluded && props.typesIncluded[QueryKeys.Artists] && items.push(...artists); |
|
|
|
useEffect(() => { |
|
if (!props.query) { return; } |
|
const q = _.cloneDeep(props.query); |
|
const r = _.cloneDeep(props.resultOrder); |
|
const t = _.cloneDeep(props.typesIncluded); |
|
|
|
const request: serverApi.QueryRequest = { |
|
query: toApiQuery(props.query), |
|
offsetsLimits: { |
|
songOffset: 0, |
|
songLimit: 5, // TODO |
|
artistOffset: 0, |
|
artistLimit: 5, |
|
tagOffset: 0, |
|
tagLimit: 5, |
|
}, |
|
ordering: toServerOrdering(props.resultOrder), |
|
} |
|
const requestOpts = { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify(request) |
|
}; |
|
fetch(serverApi.QueryEndpoint, requestOpts) |
|
.then((response: any) => response.json()) |
|
.then((json: any) => { |
|
const match = _.isEqual(q, props.query) && _.isEqual(r, props.resultOrder) && _.isEqual(t, props.typesIncluded); |
|
'songs' in json && match && setSongs(json.songs); |
|
'artists' in json && match && setArtists(json.artists); |
|
}); |
|
}, [props.query]); |
|
|
|
return <> |
|
<FormControl component='fieldset'> |
|
<FormLabel component='legend'>Query</FormLabel> |
|
<FilterControl |
|
query={props.query} |
|
onChangeQuery={props.onQueryChange} |
|
/> |
|
</FormControl> |
|
<ItemTypeCheckboxes |
|
types={props.typesIncluded || { |
|
[QueryKeys.Songs]: true, |
|
[QueryKeys.Artists]: true, |
|
[QueryKeys.Tags]: true, |
|
}} |
|
onChange={props.onTypesChange} |
|
/> |
|
<OrderingWidget |
|
ordering={props.resultOrder || { |
|
[QueryKeys.OrderBy]: { |
|
[QueryKeys.OrderKey]: OrderKey.Name |
|
}, |
|
[QueryKeys.Ascending]: true |
|
}} |
|
onChange={props.onOrderChange} |
|
/> |
|
<BrowseWindow items={items} /> |
|
</> |
|
}
|
|
|