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.
 
 
 
 

163 lines
5.2 KiB

import React, { useEffect } from 'react';
import { createMuiTheme, Box, LinearProgress } from '@material-ui/core';
import { QueryElem, toApiQuery } from '../../lib/query/Query';
import QueryBuilder from '../querybuilder/QueryBuilder';
import * as serverApi from '../../api';
import { SongTable } from '../tables/ResultsTable';
import stringifyList from '../../lib/stringifyList';
import { getArtists, getSongTitles, getAlbums, getTags } from '../../lib/query/Getters';
import { grey } from '@material-ui/core/colors';
import { WindowState } from './Windows';
var _ = require('lodash');
const darkTheme = createMuiTheme({
palette: {
type: 'dark',
primary: {
main: grey[100],
}
},
});
export interface ResultsForQuery {
for: QueryElem,
results: any[],
};
export interface QueryWindowState extends WindowState {
editingQuery: boolean,
query: QueryElem | null,
resultsForQuery: ResultsForQuery | null,
}
export enum QueryWindowStateActions {
SetQuery = "setQuery",
SetEditingQuery = "setEditingQuery",
SetResultsForQuery = "setResultsForQuery",
}
export function QueryWindowReducer(state: QueryWindowState, action: any) {
switch (action.type) {
case QueryWindowStateActions.SetQuery:
return { ...state, query: action.value }
case QueryWindowStateActions.SetEditingQuery:
return { ...state, editingQuery: action.value }
case QueryWindowStateActions.SetResultsForQuery:
return { ...state, resultsForQuery: action.value }
default:
throw new Error("Unimplemented QueryWindow state update.")
}
}
export interface IProps {
state: QueryWindowState,
dispatch: (action: any) => void,
mainDispatch: (action: any) => void,
}
export default function QueryWindow(props: IProps) {
let query = props.state.query;
let editing = props.state.editingQuery;
let resultsFor = props.state.resultsForQuery;
let setQuery = (q: QueryElem | null) => {
props.dispatch({ type: QueryWindowStateActions.SetQuery, value: q });
}
let setEditingQuery = (e: boolean) => {
props.dispatch({ type: QueryWindowStateActions.SetEditingQuery, value: e });
}
let setResultsForQuery = (r: ResultsForQuery | null) => {
props.dispatch({ type: QueryWindowStateActions.SetResultsForQuery, value: r });
}
const loading = query && (!resultsFor || !_.isEqual(resultsFor.for, query));
const showResults = (query && resultsFor && query == resultsFor.for) ? resultsFor.results : [];
const songGetters = {
getTitle: (song: any) => song.title,
getArtistNames: (song: any) => song.artists.map((a: any) => a.name),
getArtistIds: (song: any) => song.artists.map((a: any) => a.artistId),
getAlbumNames: (song: any) => song.albums.map((a: any) => a.name),
getTagNames: (song: any) => {
// Recursively resolve the name.
const resolveTag = (tag: any) => {
var r = [tag.name];
if (tag.parent) { r.unshift(resolveTag(tag.parent)); }
return r;
}
return song.tags.map((tag: any) => resolveTag(tag));
}
}
const doQuery = async (_query: QueryElem) => {
var q: serverApi.QueryRequest = {
query: toApiQuery(_query),
offsetsLimits: {
songOffset: 0,
songLimit: 100,
},
ordering: {
orderBy: {
type: serverApi.OrderByType.Name,
},
ascending: true,
},
};
const requestOpts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(q),
};
return (async () => {
const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts)
let json: any = await response.json();
if (_.isEqual(query, _query)) {
setResultsForQuery({
for: _query,
results: json.songs,
})
}
})();
}
useEffect(() => {
if (query) {
doQuery(query);
} else {
setResultsForQuery(null);
}
}, [query]);
return <Box width="100%" justifyContent="center" display="flex" flexWrap="wrap">
<Box
m={1}
width="80%"
>
<QueryBuilder
query={query}
onChangeQuery={setQuery}
editing={editing}
onChangeEditing={setEditingQuery}
requestFunctions={{
getArtists: getArtists,
getSongTitles: getSongTitles,
getAlbums: getAlbums,
getTags: getTags,
}}
/>
</Box>
<Box
m={1}
width="80%"
>
<SongTable
songs={showResults}
songGetters={songGetters}
mainDispatch={props.mainDispatch}
/>
{loading && <LinearProgress />}
</Box>
</Box>
}