Unify the filter. Still some bugs but it looks better. Location filter looks good.

master
Sander Vocke 6 years ago
parent a098274fa8
commit 28dbc5714c
  1. 17
      src/main.js
  2. 183
      src/queries.js
  3. 130
      src/userquerywidget.js

@ -8,7 +8,7 @@ import { SearchBar } from './searchbar.js';
import { InternalErrorPage } from './error.js'; import { InternalErrorPage } from './error.js';
import { LoadingPage } from './loading.js'; import { LoadingPage } from './loading.js';
import { ProvideDB } from './database.js'; import { ProvideDB } from './database.js';
import { UserQuery, user_query_from_search_string, maybe_image_query, do_image_query, maybe_album_query, do_album_query, maybe_tag_query, do_tag_query, ConstFilter, ResultTypeEnum } from './queries.js'; import { UserQuery, user_query_from_search_string, maybe_image_query, do_image_query, maybe_album_query, do_album_query, maybe_tag_query, do_tag_query, ConstFilter } from './queries.js';
import { Browser } from './browser.js'; import { Browser } from './browser.js';
import { UserQueryWidget } from './userquerywidget.js'; import { UserQueryWidget } from './userquerywidget.js';
import { ResultsView } from './resultsview.js'; import { ResultsView } from './resultsview.js';
@ -53,8 +53,7 @@ export function LoadedMainPage(props) {
useEffect(() => { useEffect(() => {
// Single-fire effect to start retrieving the albums and tags lists. // Single-fire effect to start retrieving the albums and tags lists.
var blank_user_query = new UserQuery(); var blank_user_query = new UserQuery();
blank_user_query.album_filter = new ConstFilter(ResultTypeEnum.ALBUM, true); blank_user_query.filter = new ConstFilter(true);
blank_user_query.tag_filter = new ConstFilter(ResultTypeEnum.TAG, true);
var sql_album_query = maybe_album_query(blank_user_query); var sql_album_query = maybe_album_query(blank_user_query);
var sql_tag_query = maybe_tag_query(blank_user_query); var sql_tag_query = maybe_tag_query(blank_user_query);
@ -109,13 +108,13 @@ export function LoadedMainPage(props) {
} }
function onNewQuery(q) { function onNewQuery(q) {
var do_update_photos = !_.isEqual(q.image_filter, gallery_user_query.image_filter); var do_update = !_.isEqual(q.filter, gallery_user_query.filter);
var do_update_albums = !_.isEqual(q.album_filter, gallery_user_query.album_filter);
var do_update_tags = !_.isEqual(q.tag_filter, gallery_user_query.tag_filter);
setGalleryUserQuery(q); setGalleryUserQuery(q);
if (do_update_photos) { updatePhotos(q); } if (do_update) {
if (do_update_albums) { updateAlbums(q); } updatePhotos(q);
if (do_update_tags) { updateTags(q); } updateAlbums(q);
updateTags(q);
}
} }
function onSearch(q) { function onSearch(q) {

@ -89,16 +89,15 @@ export const MatchTypeEnum = {
MATCH_TAG_NAME_EQUALS: 10, // Match on the local tag name (excluding parents) MATCH_TAG_NAME_EQUALS: 10, // Match on the local tag name (excluding parents)
} }
/*
export const ResultTypeEnum = { export const ResultTypeEnum = {
IMAGE: 1, IMAGE: 1,
ALBUM: 2, ALBUM: 2,
TAG: 3, TAG: 3,
} }
*/
export class ResultFilter { export class ResultFilter {
constructor(type) { this.result_type = type; }
result_type = ResultTypeEnum.IMAGE;
to_sql_where() { return "(1=1)"; } to_sql_where() { return "(1=1)"; }
is_true() { return false; } is_true() { return false; }
@ -108,7 +107,7 @@ export class ResultFilter {
} }
export class ConstFilter extends ResultFilter { export class ConstFilter extends ResultFilter {
constructor(type, val) { super(type); this.constval = val; } constructor(val) { super(); this.constval = val; }
constval = true; // True lets everything through, false rejects everything constval = true; // True lets everything through, false rejects everything
to_sql_where() { to_sql_where() {
@ -121,12 +120,12 @@ export class ConstFilter extends ResultFilter {
} }
export class NegationFilter extends ResultFilter { export class NegationFilter extends ResultFilter {
constructor(rtype, body) { constructor(body) {
super(rtype); super();
this.body = body; this.body = body;
} }
body = new ConstFilter(this.return_type, false); body = new ConstFilter(false);
to_sql_where() { to_sql_where() {
return "NOT (" + this.body.to_sql_where() + ")"; return "NOT (" + this.body.to_sql_where() + ")";
@ -137,10 +136,10 @@ export class NegationFilter extends ResultFilter {
simplify() { simplify() {
var f = this.body.simplify(); var f = this.body.simplify();
if (f.is_true()) { if (f.is_true()) {
return new ConstFilter(this.result_type, false); return new ConstFilter(false);
} }
if (f.is_false()) { if (f.is_false()) {
return new ConstFilter(this.result_type, true); return new ConstFilter(true);
} }
if (f.is_negation()) { if (f.is_negation()) {
return f.body; return f.body;
@ -155,8 +154,8 @@ export const TimeFilterTypeEnum = {
} }
export class TimeFilter extends ResultFilter { export class TimeFilter extends ResultFilter {
constructor(rtype, time, type) { constructor(time, type) {
super(rtype); super();
this.time = time; this.time = time;
this.type = type; this.type = type;
} }
@ -186,8 +185,8 @@ export const ImageTypeEnum = {
} }
export class ImageTypeFilter extends ResultFilter { export class ImageTypeFilter extends ResultFilter {
constructor(rtype, type) { constructor(type) {
super(rtype); super();
this.type = type; this.type = type;
} }
@ -202,8 +201,8 @@ export class ImageTypeFilter extends ResultFilter {
} }
export class MatchingFilter extends ResultFilter { export class MatchingFilter extends ResultFilter {
constructor(rtype, from, mtype) { constructor(from, mtype) {
super(rtype); super();
this.match_from = from; this.match_from = from;
this.match_type = mtype; this.match_type = mtype;
} }
@ -258,14 +257,16 @@ export const LogicalOperatorEnum = {
} }
export class LogicalOperatorFilter extends ResultFilter { export class LogicalOperatorFilter extends ResultFilter {
constructor(type, a, b, op) { super(type); this.sub_filter_a = a; this.sub_filter_b = b; this.operator = op; } constructor(operands, op) { super(); this.operands = operands; this.operator = op; }
sub_filter_a = false; operands = false;
sub_filter_b = false;
operator = LogicalOperatorEnum.AND; operator = LogicalOperatorEnum.AND;
to_sql_where() { to_sql_where() {
var where1 = this.sub_filter_a.to_sql_where(); var operand_wheres = [];
var where2 = this.sub_filter_b.to_sql_where(); for (let i = 0; i < this.operands.length; i++) {
operand_wheres.push(this.operands[i].to_sql_where());
}
var operator_str = ""; var operator_str = "";
if (this.operator === LogicalOperatorEnum.AND) { if (this.operator === LogicalOperatorEnum.AND) {
operator_str = " AND "; operator_str = " AND ";
@ -274,30 +275,51 @@ export class LogicalOperatorFilter extends ResultFilter {
} else { } else {
throw new Error('Unsupported logical operator: ' + this.operator); throw new Error('Unsupported logical operator: ' + this.operator);
} }
return "(" + where1 + operator_str + where2 + ")"; var retstr = "(" + operand_wheres[0];
for (let i = 1; i < this.operands.length; i++) {
retstr += operator_str + operand_wheres[i];
}
retstr += ")";
return retstr;
} }
simplify() { simplify() {
var a = this.sub_filter_a.simplify(); var simple = [];
var b = this.sub_filter_b.simplify(); for (let i = 0; i < this.operands.length; i++) {
simple.push(this.operands[i].simplify());
}
if (this.operator === LogicalOperatorEnum.OR) { if (this.operator === LogicalOperatorEnum.OR) {
if (a.is_true() || b.is_true()) { for (let i = simple.length - 1; i >= 0; i--) {
return new ConstFilter(this.return_type, true); if (simple[i].is_true()) {
return new ConstFilter(true);
}
if (simple[i].is_false()) {
// Remove this element, because OR FALSE means nothing
simple.splice(i, 1);
}
} }
if (a.is_false()) { return b; }
if (b.is_false()) { return a; }
} }
if (this.operator === LogicalOperatorEnum.AND) { if (this.operator === LogicalOperatorEnum.AND) {
if (a.is_false() || b.is_false()) { for (let i = simple.length - 1; i >= 0; i--) {
return new ConstFilter(this.return_type, false); if (simple[i].is_false()) {
return new ConstFilter(false);
}
if (simple[i].is_true()) {
// Remove this element, because AND TRUE means nothing
simple.splice(i, 1);
}
} }
if (a.is_true()) { return b; }
if (b.is_true()) { return a; }
} }
return this; if(simple.length == 0) {
return null;
} else if(simple.length == 1) {
return simple[0];
}
return new LogicalOperatorFilter(simple, this.operator);
} }
} }
@ -306,8 +328,8 @@ export class LocationFilter extends ResultFilter {
// to a location and filters objects outside said location. // to a location and filters objects outside said location.
// Locations are directly stored from Nominatim API responses, // Locations are directly stored from Nominatim API responses,
// which have GeoJSON and other metadata. // which have GeoJSON and other metadata.
constructor(rtype, geo_area) { constructor(geo_area) {
super(rtype); super();
this.geo_area = geo_area; this.geo_area = geo_area;
} }
@ -327,9 +349,7 @@ export class LocationFilter extends ResultFilter {
} }
export class UserQuery { export class UserQuery {
image_filter = new ConstFilter(ResultTypeEnum.IMAGE, false); filter = new ConstFilter(false);
album_filter = new ConstFilter(ResultTypeEnum.ALBUM, false);
tag_filter = new ConstFilter(ResultTypeEnum.TAG, false);
} }
// This query will return database entries with the fields "id", "uniqueHash", "relativePath" (of the album) and "name" for each matching image. // This query will return database entries with the fields "id", "uniqueHash", "relativePath" (of the album) and "name" for each matching image.
@ -378,24 +398,24 @@ export function tag_query_with_where(maybe_where) {
export function maybe_image_query(user_query, database) { export function maybe_image_query(user_query, database) {
var where = false; var where = false;
if (user_query.image_filter) { if (user_query.filter) {
where = "WHERE " + user_query.image_filter.to_sql_where(); where = "WHERE " + user_query.filter.to_sql_where();
} }
return image_query_with_where(where, database); return image_query_with_where(where, database);
} }
export function maybe_album_query(user_query, database) { export function maybe_album_query(user_query, database) {
var where = false; var where = false;
if (user_query.album_filter) { if (user_query.filter) {
where = "WHERE " + user_query.album_filter.to_sql_where(); where = "WHERE " + user_query.filter.to_sql_where();
} }
return album_query_with_where(where, database); return album_query_with_where(where, database);
} }
export function maybe_tag_query(user_query) { export function maybe_tag_query(user_query) {
var where = false; var where = false;
if (user_query.tag_filter) { if (user_query.filter) {
where = "WHERE " + user_query.tag_filter.to_sql_where(); where = "WHERE " + user_query.filter.to_sql_where();
} }
return tag_query_with_where(where); return tag_query_with_where(where);
} }
@ -408,51 +428,31 @@ export function filter_is_const_false(filter) {
return false; return false;
} }
function filter_from_text_segment(result_type, segment) { function filter_from_text_segment(segment) {
var filter = false; var filter = false;
var name_filter;
if (result_type === ResultTypeEnum.IMAGE) {
// Option 1: match on image name // Option 1: match on image name
name_filter = new MatchingFilter( var image_filter = new MatchingFilter(
result_type,
segment['text'], segment['text'],
MatchTypeEnum.MATCH_IMAGE_NAME_NATURAL MatchTypeEnum.MATCH_IMAGE_NAME_NATURAL
); );
// Option 2: match on album path (TODO: need natural matching) // Option 2: match on album path (TODO: need natural matching)
var album_filter = new MatchingFilter( var album_filter = new MatchingFilter(
result_type,
segment['text'], segment['text'],
MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS_OR_CHILD MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD
); );
filter = new LogicalOperatorFilter(result_type, name_filter, album_filter, LogicalOperatorEnum.OR); // Option 3: match on tag name
if (segment['negated']) {
filter = new NegationFilter(result_type, filter);
}
} else if (result_type === ResultTypeEnum.ALBUM) {
// TODO: We need a natural matcher for album names
name_filter = new MatchingFilter(
result_type,
segment['text'],
MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS_OR_CHILD
);
filter = name_filter;
if (segment['negated']) {
filter = new NegationFilter(result_type, filter);
}
} else if (result_type === ResultTypeEnum.TAG) {
// TODO: We need a natural matcher for tag names // TODO: We need a natural matcher for tag names
name_filter = new MatchingFilter( var tag_filter = new MatchingFilter(
result_type,
segment['text'], segment['text'],
MatchTypeEnum.MATCH_TAG_NAME_EQUALS_OR_CHILD MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD
); );
filter = name_filter;
filter = new LogicalOperatorFilter([image_filter, album_filter, tag_filter], LogicalOperatorEnum.OR);
if (segment['negated']) { if (segment['negated']) {
filter = new NegationFilter(result_type, filter); filter = new NegationFilter(filter);
}
} }
return filter.simplify(); return filter.simplify();
@ -468,12 +468,8 @@ export function user_query_from_search_string(search_string) {
var r = new UserQuery(); var r = new UserQuery();
texts.forEach(text => { texts.forEach(text => {
r.image_filter = new LogicalOperatorFilter(ResultTypeEnum.IMAGE, r.image_filter, r.filter = new LogicalOperatorFilter([r.filter, filter_from_text_segment(text)],
filter_from_text_segment(ResultTypeEnum.IMAGE, text), LogicalOperatorEnum.AND).simplify(); LogicalOperatorEnum.OR).simplify();
r.album_filter = new LogicalOperatorFilter(ResultTypeEnum.ALBUM, r.album_filter,
filter_from_text_segment(ResultTypeEnum.ALBUM, text), LogicalOperatorEnum.AND).simplify();
r.tag_filter = new LogicalOperatorFilter(ResultTypeEnum.TAG, r.tag_filter,
filter_from_text_segment(ResultTypeEnum.TAG, text), LogicalOperatorEnum.AND).simplify();
}); });
return r; return r;
@ -481,21 +477,8 @@ export function user_query_from_search_string(search_string) {
export function user_query_from_browsed_album(album_path) { export function user_query_from_browsed_album(album_path) {
var r = new UserQuery(); var r = new UserQuery();
r.image_filter = r.filter =
new MatchingFilter(
ResultTypeEnum.IMAGE,
album_path,
MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD,
false).simplify();
r.album_filter =
new MatchingFilter(
ResultTypeEnum.ALBUM,
album_path,
MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD,
false).simplify();
r.tag_filter =
new MatchingFilter( new MatchingFilter(
ResultTypeEnum.TAG,
album_path, album_path,
MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD, MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD,
false).simplify(); false).simplify();
@ -504,24 +487,10 @@ export function user_query_from_browsed_album(album_path) {
export function user_query_from_browsed_tag(tag_path) { export function user_query_from_browsed_tag(tag_path) {
var r = new UserQuery(); var r = new UserQuery();
r.image_filter = r.filter =
new MatchingFilter( new MatchingFilter(
ResultTypeEnum.IMAGE,
tag_path, tag_path,
MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD, MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD,
false).simplify(); false).simplify();
r.album_filter =
new MatchingFilter(
ResultTypeEnum.ALBUM,
tag_path,
MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD,
false).simplify();
r.tag_filter =
new MatchingFilter(
ResultTypeEnum.TAG,
tag_path,
MatchTypeEnum.MATCH_TAG_EQUALS_OR_CHILD,
false).simplify();
return r; return r;
} }

@ -17,6 +17,7 @@ import Select from '@material-ui/core/Select';
import TextField from '@material-ui/core/TextField'; import TextField from '@material-ui/core/TextField';
import ScheduleIcon from '@material-ui/icons/Schedule'; import ScheduleIcon from '@material-ui/icons/Schedule';
import VideocamIcon from '@material-ui/icons/Videocam'; import VideocamIcon from '@material-ui/icons/Videocam';
import LocationOnIcon from '@material-ui/icons/LocationOn';
import { MuiPickersUtilsProvider, DateTimePicker } from "@material-ui/pickers"; import { MuiPickersUtilsProvider, DateTimePicker } from "@material-ui/pickers";
import DateFnsUtils from '@date-io/date-fns'; import DateFnsUtils from '@date-io/date-fns';
@ -30,7 +31,7 @@ import { SearchBar } from './searchbar.js';
import { import {
filter_is_const_false, ConstFilter, LogicalOperatorFilter, MatchingFilter, filter_is_const_false, ConstFilter, LogicalOperatorFilter, MatchingFilter,
ResultTypeEnum, LogicalOperatorEnum, MatchTypeEnum, NegationFilter, TimeFilterTypeEnum, LogicalOperatorEnum, MatchTypeEnum, NegationFilter, TimeFilterTypeEnum,
TimeFilter, ImageTypeFilter, ImageTypeEnum, LocationFilter TimeFilter, ImageTypeFilter, ImageTypeEnum, LocationFilter
} from './queries.js' } from './queries.js'
import { Typography } from '@material-ui/core'; import { Typography } from '@material-ui/core';
@ -82,7 +83,6 @@ export function EditLocationFilterExpression(props) {
setGeoLayers([layer]); setGeoLayers([layer]);
// Update the proposed polygon // Update the proposed polygon
console.log("Updated proposal:", result);
setProposal(result); setProposal(result);
} }
@ -94,7 +94,6 @@ export function EditLocationFilterExpression(props) {
// Do a geometry query. // Do a geometry query.
query_geometry(query) query_geometry(query)
.then(result => { .then(result => {
console.log("Query result:", result);
if (result) { if (result) {
updateProposal(result); updateProposal(result);
} }
@ -327,15 +326,15 @@ export function EditFilterExpressionDialog(props) {
const handleTypeChange = e => { const handleTypeChange = e => {
var val = e.target.value; var val = e.target.value;
if (val == FilterTypeEnum.CONST) { if (val == FilterTypeEnum.CONST) {
setFilter(new ConstFilter(filter.result_type, true)); setFilter(new ConstFilter(true));
} else if (val == FilterTypeEnum.MATCHING) { } else if (val == FilterTypeEnum.MATCHING) {
setFilter(new MatchingFilter(filter.result_type, "", MatchTypeEnum.MATCH_IMAGE_NAME_NATURAL)); setFilter(new MatchingFilter("", MatchTypeEnum.MATCH_IMAGE_NAME_NATURAL));
} else if (val == FilterTypeEnum.TIME) { } else if (val == FilterTypeEnum.TIME) {
setFilter(new TimeFilter(filter.result_type, Date.now(), TimeFilterTypeEnum.AFTER)); setFilter(new TimeFilter(Date.now(), TimeFilterTypeEnum.AFTER));
} else if (val == FilterTypeEnum.IMAGETYPE) { } else if (val == FilterTypeEnum.IMAGETYPE) {
setFilter(new ImageTypeFilter(filter.result_type, ImageTypeEnum.PHOTO)); setFilter(new ImageTypeFilter(ImageTypeEnum.PHOTO));
} else if (val == FilterTypeEnum.LOCATION) { } else if (val == FilterTypeEnum.LOCATION) {
setFilter(new LocationFilter(filter.result_type, [[0.0, 0.0]])); setFilter(new LocationFilter([[0.0, 0.0]]));
} else { } else {
throw new Error('Unsupported filter type: ' + val); throw new Error('Unsupported filter type: ' + val);
} }
@ -521,24 +520,14 @@ export function LogicalOperatorFilterExpressionControl(props) {
} }
var _ = require('lodash'); var _ = require('lodash');
const handleAChanged = (new_a) => { const handleOpChanged = (idx, new_op) => {
if (new_a == null) {
onChange(expr.sub_filter_b);
return;
}
var new_me = _.cloneDeep(expr); var new_me = _.cloneDeep(expr);
new_me.sub_filter_a = new_a;
onChange(new_me);
}
const handleBChanged = (new_b) => {
if (new_b == null) {
onChange(expr.sub_filter_a);
return;
}
var new_me = _.cloneDeep(expr); if (new_op == null) {
new_me.sub_filter_b = new_b; new_me.operands.splice(idx, 1);
} else {
new_me.operands[idx] = new_op;
}
onChange(new_me); onChange(new_me);
} }
@ -546,16 +535,19 @@ export function LogicalOperatorFilterExpressionControl(props) {
<> <>
<Box className={classes.logic_op_outer}> <Box className={classes.logic_op_outer}>
<Box className={classes.logic_op_sbs}> <Box className={classes.logic_op_sbs}>
{expr.operands.map((operand, idx) => {
const handleChange = new_op => {
handleOpChanged(idx, new_op);
};
return (<>
<Box> <Box>
<Box className={classes.logic_op_subexpr}> <Box className={classes.logic_op_subexpr}>
<FilterExpressionControl expr={expr.sub_filter_a} onChange={handleAChanged} mayBeRemoved={true} /> <FilterExpressionControl expr={operand} onChange={handleChange} mayBeRemoved={true} />
</Box>
</Box>
<Box>
<Box className={classes.logic_op_subexpr}>
<FilterExpressionControl expr={expr.sub_filter_b} onChange={handleBChanged} mayBeRemoved={true} />
</Box> </Box>
</Box> </Box>
</>);
})}
</Box> </Box>
<Button <Button
variant="outlined" variant="outlined"
@ -567,7 +559,7 @@ export function LogicalOperatorFilterExpressionControl(props) {
</Button> </Button>
</Box> </Box>
</> </>
) );
} }
export function ConstFilterExpressionControl(props) { export function ConstFilterExpressionControl(props) {
@ -677,7 +669,7 @@ export function ImageTypeFilterExpressionControl(props) {
export function LocationFilterExpressionControl(props) { export function LocationFilterExpressionControl(props) {
const classes = useStyles(); const classes = useStyles();
const { expr, onClick, onChange } = props; const { expr, onClick } = props;
return ( return (
<Button <Button
@ -685,8 +677,9 @@ export function LocationFilterExpressionControl(props) {
className={classes.filterexpcontrol} className={classes.filterexpcontrol}
aria-controls="simple-menu" aria-haspopup="true" aria-controls="simple-menu" aria-haspopup="true"
onClick={onClick} onClick={onClick}
startIcon={<LocationOnIcon />}
> >
LOCATION {expr.geo_area.display_name}
</Button> </Button>
); );
} }
@ -763,7 +756,7 @@ export function FilterExpressionControl(props) {
const handleNegation = () => { const handleNegation = () => {
handleCloseMenu(); handleCloseMenu();
var new_filter = new NegationFilter(expr.result_type, expr); var new_filter = new NegationFilter(expr);
onChange(new_filter.simplify()); onChange(new_filter.simplify());
} }
@ -818,18 +811,7 @@ export function FilterExpressionControl(props) {
export function FilterControl(props) { export function FilterControl(props) {
const classes = useStyles(); const classes = useStyles();
const { filter, onChange, resultType, resultTypeString } = props; const { filter, onChange } = props;
const enabled = !filter_is_const_false(filter);
function handleResultToggled() {
if (enabled) {
onChange(new ConstFilter(resultType, false));
}
else {
onChange(new ConstFilter(resultType, true));
}
}
// The root node may in principle never be removed, // The root node may in principle never be removed,
// except if it is a transformation node (then the body becomes the new root). // except if it is a transformation node (then the body becomes the new root).
@ -838,16 +820,6 @@ export function FilterControl(props) {
return ( return (
<> <>
<Box className={classes.filtercontrol}> <Box className={classes.filtercontrol}>
<FormControlLabel
control={
<Switch
checked={enabled}
onChange={handleResultToggled}
color="primary"
/>
}
label={resultTypeString + ':'}
/>
<FilterExpressionControl expr={filter} onChange={onChange} mayBeRemoved={may_be_removed} /> <FilterExpressionControl expr={filter} onChange={onChange} mayBeRemoved={may_be_removed} />
</Box> </Box>
</> </>
@ -856,55 +828,17 @@ export function FilterControl(props) {
export function UserQueryWidget(props) { export function UserQueryWidget(props) {
const { userQuery, onChange } = props; const { userQuery, onChange } = props;
const classes = useStyles();
var _ = require('lodash'); var _ = require('lodash');
function handleImageFilterChange(filter) { function handleFilterChange(filter) {
var q = _.cloneDeep(userQuery);
q.image_filter = filter;
onChange(q);
}
function handleAlbumFilterChange(filter) {
var q = _.cloneDeep(userQuery); var q = _.cloneDeep(userQuery);
q.album_filter = filter; q.filter = filter;
onChange(q);
}
function handleTagFilterChange(filter) {
var q = _.cloneDeep(userQuery);
q.tag_filter = filter;
onChange(q); onChange(q);
} }
return ( return (
<>
<Box className={classes.bordered + " " + classes.margined}>
<Box className={classes.margined}>
<FilterControl
filter={userQuery.image_filter}
onChange={handleImageFilterChange}
resultType={ResultTypeEnum.IMAGE}
resultTypeString="Images" />
</Box>
</Box>
<Box className={classes.bordered + " " + classes.margined}>
<Box className={classes.margined}>
<FilterControl <FilterControl
filter={userQuery.album_filter} filter={userQuery.filter}
onChange={handleAlbumFilterChange} onChange={handleFilterChange} />
resultType={ResultTypeEnum.ALBUM}
resultTypeString="Albums" />
</Box>
</Box >
<Box className={classes.bordered + " " + classes.margined}>
<Box className={classes.margined}>
<FilterControl
filter={userQuery.tag_filter}
onChange={handleTagFilterChange}
resultType={ResultTypeEnum.TAG}
resultTypeString="Tags" />
</Box>
</Box >
</>
); );
} }
Loading…
Cancel
Save