Got basic queries in result table working.

pull/16/head
Sander Vocke 5 years ago
parent 9c9d1b6dd8
commit ce2d814506
  1. 103
      client/src/components/Window.tsx
  2. 18
      client/src/components/querybuilder/QBLeafElem.tsx
  3. 49
      client/src/components/tables/ResultsTable.tsx
  4. 34
      client/src/lib/query/Query.tsx

@ -1,9 +1,10 @@
import React, { useState } from 'react';
import { ThemeProvider, CssBaseline, createMuiTheme } from '@material-ui/core';
import { QueryElem } from '../lib/query/Query';
import React, { useState, useEffect } from 'react';
import { ThemeProvider, CssBaseline, createMuiTheme, AppBar, Box } from '@material-ui/core';
import { QueryElem, toApiQuery } from '../lib/query/Query';
import QueryBuilder from './querybuilder/QueryBuilder';
import * as serverApi from '../api';
import { queryAllByRole } from '@testing-library/react';
import { SongTable } from './tables/ResultsTable';
var _ = require('lodash');
const darkTheme = createMuiTheme({
palette: {
@ -82,17 +83,95 @@ export async function getSongTitles(filter: string) {
}
export default function Window(props: any) {
interface ResultsFor {
for: QueryElem,
results: any[],
};
const [query, setQuery] = useState<QueryElem | null>(null);
const [resultsFor, setResultsFor] = useState<ResultsFor | null>(null);
const loading = query && (!resultsFor || !_.isEqual(resultsFor.for, query));
const showResults = (query && resultsFor && query == resultsFor.for) ? resultsFor.results : [];
const songGetters = {
getTitle: (song: any) => song.title,
getArtist: (song: any) => "Artist",
getAlbum: (song: any) => "Album",
}
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)) {
setResultsFor({
for: _query,
results: json.songs,
})
}
})();
}
useEffect(() => {
if (query) {
doQuery(query);
} else {
setResultsFor(null);
}
}, [query]);
return <ThemeProvider theme={darkTheme}>
<CssBaseline />
<QueryBuilder
query={query}
onChangeQuery={setQuery}
requestFunctions={{
getArtists: getArtists,
getSongTitles: getSongTitles,
}}
/>
<AppBar position="static" style={{ background: 'grey' }}>
<Box m={0.5} display="flex" alignItems="center">
<img height="30px" src={process.env.PUBLIC_URL + "/logo.svg"} alt="error"></img>
</Box>
</AppBar>
<Box width="100%" justifyContent="center" display="flex" flexWrap="wrap">
<Box
m={1}
width="80%"
>
<QueryBuilder
query={query}
onChangeQuery={setQuery}
requestFunctions={{
getArtists: getArtists,
getSongTitles: getSongTitles,
}}
/>
</Box>
<Box
m={1}
width="80%"
>
<SongTable
songs={showResults}
songGetters={songGetters}
/>
</Box>
</Box>
</ThemeProvider>
}

@ -2,7 +2,7 @@ import React from 'react';
import { QueryLeafElem, QueryLeafBy, QueryLeafOp, QueryElem } from '../../lib/query/Query';
import { Chip, Typography, IconButton, Box } from '@material-ui/core';
import { QBPlaceholder } from './QBPlaceholder';
import CloseIcon from '@material-ui/icons/Close';
import DeleteIcon from '@material-ui/icons/Delete';
import { Requests } from './QueryBuilder';
export interface ElemChipProps {
@ -56,8 +56,12 @@ export interface DeleteButtonProps {
}
export function QBQueryElemDeleteButton(props: DeleteButtonProps) {
return <IconButton onClick={props.onClick} size="small">
<CloseIcon />
return <IconButton
onClick={props.onClick}
disableRipple={true}
size="small"
>
<DeleteIcon />
</IconButton>
}
@ -72,9 +76,11 @@ export function QBLeafElem(props: IProps) {
let e = props.elem;
const extraElements = props.editingQuery ?
<QBQueryElemDeleteButton
onClick={() => props.onReplace(null)}
/>
<Box m={0.5}>
<QBQueryElemDeleteButton
onClick={() => props.onReplace(null)}
/>
</Box>
: undefined;
if (e.a == QueryLeafBy.ArtistName &&

@ -0,0 +1,49 @@
import React from 'react';
import { TableContainer, Table, TableHead, TableRow, TableCell, Paper, makeStyles, TableBody } from '@material-ui/core';
export interface SongGetters {
getTitle: (song: any) => string,
getArtist: (song: any) => string,
getAlbum: (song: any) => string,
}
export interface IProps {
songs: any[],
songGetters: SongGetters,
}
export function SongTable(props: IProps) {
const useTableStyles = makeStyles({
table: {
minWidth: 650,
},
});
const classes = useTableStyles();
return (
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="a dense table">
<TableHead>
<TableRow>
<TableCell align="left">Title</TableCell>
<TableCell align="left">Artist</TableCell>
<TableCell align="left">Album</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.songs.map((song:any) => {
const title = props.songGetters.getTitle(song);
const artist = props.songGetters.getArtist(song);
const album = props.songGetters.getAlbum(song);
return <TableRow key={title}>
<TableCell align="left">{title}</TableCell>
<TableCell align="left">{artist}</TableCell>
<TableCell align="left">{album}</TableCell>
</TableRow>
})}
</TableBody>
</Table>
</TableContainer>
);
}

@ -1,3 +1,5 @@
import * as serverApi from '../../api';
export enum QueryLeafBy {
ArtistName = 0,
AlbumName,
@ -149,4 +151,36 @@ export function simplify(q: QueryElem | null): QueryElem | null {
}
return q;
}
export function toApiQuery(q: QueryElem) : serverApi.Query {
const propsMapping: any = {
[QueryLeafBy.SongTitle]: serverApi.QueryElemProperty.songTitle,
[QueryLeafBy.ArtistName]: serverApi.QueryElemProperty.artistName,
}
const leafOpsMapping: any = {
[QueryLeafOp.Equals]: serverApi.QueryFilterOp.Eq,
[QueryLeafOp.Like]: serverApi.QueryFilterOp.Like,
}
const nodeOpsMapping: any = {
[QueryNodeOp.And]: serverApi.QueryElemOp.And,
[QueryNodeOp.Or]: serverApi.QueryElemOp.Or,
}
if(isLeafElem(q)) {
const r: serverApi.QueryElem = {
prop: propsMapping[q.a],
propOperator: leafOpsMapping[q.leafOp],
propOperand: q.b,
}
return r;
} else if(isNodeElem(q)) {
const r = {
children: q.operands.map((op: any) => toApiQuery(op)),
childrenOperator: nodeOpsMapping[q.nodeOp]
}
return r;
}
return {};
}
Loading…
Cancel
Save