Got editing working for const and logical op filters.

master
Sander Vocke 6 years ago
parent 446347e2e4
commit d104aa7358
  1. 1
      src/database.js
  2. 1
      src/map.js
  3. 3
      src/queries.js
  4. 223
      src/userquerywidget.js

@ -16,7 +16,6 @@ export function alasql_async_queries(alasql_object, queries) {
var p = Promise.resolve(null);
for (let i = 0; i < queries.length; i++) {
p = p.then(() => {
console.log(queries[i]);
return alasql_object.promise(queries[i]);
});
}

@ -0,0 +1 @@
// TODO https://leafletjs.com/examples/quick-start/

@ -219,7 +219,8 @@ export class UserQuery {
// This query will return database entries with the fields "id", "uniqueHash", "relativePath" (of the album) and "name" for each matching image.
export function image_query_with_where(maybe_where) {
return "SELECT Images.id, Images.name, Images.uniqueHash, Albums.relativePath FROM Images INNER JOIN Albums ON Images.album=Albums.id LEFT JOIN ImageTags ON Images.id=ImageTags.imageid LEFT JOIN Tags ON ImageTags.tagid=Tags.id " + (maybe_where ? maybe_where : "" + " GROUP BY id;");
return "SELECT Images.id, Images.name, Images.uniqueHash, Albums.relativePath FROM Images INNER JOIN Albums ON Images.album=Albums.id LEFT JOIN ImageTags ON Images.id=ImageTags.imageid LEFT JOIN Tags ON ImageTags.tagid=Tags.id " + (maybe_where ? maybe_where : "" + ";");
// TODO: GROUP BY is not working for some reason.
}
// This query will return database entries with the fields "id" and "relativePath" for each matching album.

@ -1,13 +1,19 @@
import React from 'react';
import React, { useEffect } from 'react';
import Switch from '@material-ui/core/Switch';
import Box from '@material-ui/core/Box';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormControl from '@material-ui/core/FormControl';
import Button from '@material-ui/core/Button';
import LabelIcon from '@material-ui/icons/Label';
import ImportContactsIcon from '@material-ui/icons/ImportContacts';
import PhotoIcon from '@material-ui/icons/Photo';
import SearchIcon from '@material-ui/icons/Search';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import DialogTitle from '@material-ui/core/DialogTitle';
import Dialog from '@material-ui/core/Dialog';
import Select from '@material-ui/core/Select';
import { makeStyles } from '@material-ui/core/styles';
@ -40,14 +46,110 @@ const useStyles = makeStyles(theme => ({
},
}));
export function EditConstFilterExpression(props) {
const { onChange, filter } = props;
var _ = require('lodash');
function handleResultToggled() {
var newfilter = _.cloneDeep(filter);
newfilter.constval = !filter.constval;
onChange(newfilter);
}
return (
<FormControlLabel
control={
<Switch
checked={filter.constval}
onChange={handleResultToggled}
color="primary"
/>
}
label={filter.constval ? "TRUE" : "FALSE"}
/>
);
}
export function EditLogicalOperatorFilterExpression(props) {
const { onChange, filter } = props;
var _ = require('lodash');
const id = _.uniqueId("logic_op_");
const labelid = _.uniqueId("logic_op_label_");
function handleChange(e) {
console.log("changing to value: ", e.target.value);
var newfilter = _.cloneDeep(filter);
newfilter.operator = e.target.value;
onChange(newfilter);
}
return (
<FormControl>
<Select
labelId={labelid}
id={id}
value={filter.operator}
onChange={handleChange}
>
<MenuItem value={LogicalOperatorEnum.AND}>AND</MenuItem>
<MenuItem value={LogicalOperatorEnum.OR}>OR</MenuItem>
</Select>
</FormControl>
);
}
export function EditFilterExpressionDialog(props) {
const classes = useStyles();
const { onClose, startingFilter, open } = props;
const [filter, setFilter] = React.useState(startingFilter);
useEffect(() => {
setFilter(startingFilter);
}, [startingFilter]);
const handleClose = () => {
onClose(filter);
};
var _ = require('lodash');
const id = _.uniqueId("simple_dialog_title_");
var control = <></>;
var subprops = {
onChange: setFilter,
filter: filter,
};
if (filter instanceof ConstFilter) {
control = <EditConstFilterExpression {...subprops} />
} else if (filter instanceof LogicalOperatorFilter) {
control = <EditLogicalOperatorFilterExpression {...subprops} />
}/* else if (expr instanceof MatchingFilter) {
filter_elem = <MatchingFilterExpressionControl {...props} onClick={handleClick} />
}*/
return (
<Dialog aria-labelledby={id} open={open}>
<DialogTitle id={id}>Edit expression</DialogTitle>
{control}
<Button onClick={handleClose}>
Done
</Button>
</Dialog>
);
}
export function TagEqualsExpressionControl(props) {
const classes = useStyles();
const { name } = props;
const { name, onClick } = props;
return (
<>
<Button
variant="outlined"
className={classes.filterexpcontrol}
aria-controls="simple-menu" aria-haspopup="true"
onClick={onClick}
startIcon={<LabelIcon />}>
{name}
</Button>
@ -57,12 +159,14 @@ export function TagEqualsExpressionControl(props) {
export function AlbumEqualsExpressionControl(props) {
const classes = useStyles();
const { name } = props;
const { name, onClick } = props;
return (
<>
<Button
variant="outlined"
className={classes.filterexpcontrol}
aria-controls="simple-menu" aria-haspopup="true"
onClick={onClick}
startIcon={<ImportContactsIcon />}>
{name}
</Button>
@ -72,12 +176,14 @@ export function AlbumEqualsExpressionControl(props) {
export function ImageNameEqualsExpressionControl(props) {
const classes = useStyles();
const { name } = props;
const { name, onClick } = props;
return (
<>
<Button
variant="outlined"
className={classes.filterexpcontrol}
aria-controls="simple-menu" aria-haspopup="true"
onClick={onClick}
startIcon={<PhotoIcon />}>
{name}
</Button>
@ -87,12 +193,14 @@ export function ImageNameEqualsExpressionControl(props) {
export function ImageNameNaturalMatchExpressionControl(props) {
const classes = useStyles();
const { name } = props;
const { name, onClick } = props;
return (
<>
<Button
variant="outlined"
className={classes.filterexpcontrol}
aria-controls="simple-menu" aria-haspopup="true"
onClick={onClick}
startIcon={<><PhotoIcon /><SearchIcon /></>}>
{name}
</Button>
@ -102,23 +210,23 @@ export function ImageNameNaturalMatchExpressionControl(props) {
export function MatchingFilterExpressionControl(props) {
const classes = useStyles();
const { expr } = props;
const { expr, onClick } = props;
var pretty_name = expr.match_from
.replace(/^"/g, '')
.replace(/"$/g, '');
if (expr.match_type === MatchTypeEnum.MATCH_TAG_EQUALS) {
return <TagEqualsExpressionControl name={pretty_name} />
return <TagEqualsExpressionControl name={pretty_name} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_ALBUM_EQUALS) {
return <AlbumEqualsExpressionControl name={pretty_name} />
return <AlbumEqualsExpressionControl name={pretty_name} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_ALBUM_EQUALS_OR_CHILD) {
return <AlbumEqualsExpressionControl name={pretty_name + '(/...)'} />
return <AlbumEqualsExpressionControl name={pretty_name + '(/...)'} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_IMAGE_NAME_EQUALS) {
return <ImageNameEqualsExpressionControl name={pretty_name} />
return <ImageNameEqualsExpressionControl name={pretty_name} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_IMAGE_NAME_NATURAL) {
return <ImageNameNaturalMatchExpressionControl name={pretty_name} />
return <ImageNameNaturalMatchExpressionControl name={pretty_name} onClick={onClick} />
} else if (expr.match_type === MatchTypeEnum.MATCH_ALBUM_NAME_EQUALS) {
return <AlbumEqualsExpressionControl name={'(.../)' + pretty_name + '(/...)'} />
return <AlbumEqualsExpressionControl name={'(.../)' + pretty_name + '(/...)'} onClick={onClick} />
}
throw new Error('Cannot render matching filter control: unsupported type.');
@ -126,7 +234,7 @@ export function MatchingFilterExpressionControl(props) {
export function LogicalOperatorFilterExpressionControl(props) {
const classes = useStyles();
const { expr } = props;
const { expr, onClick, onChange } = props;
var opstring = "";
if (expr.operator === LogicalOperatorEnum.AND) {
@ -135,24 +243,39 @@ export function LogicalOperatorFilterExpressionControl(props) {
opstring = " OR ";
}
var _ = require('lodash');
const handleAChanged = (new_a) => {
var new_me = _.cloneDeep(expr);
new_me.sub_filter_a = new_a;
onChange(new_me);
}
const handleBChanged = (new_b) => {
var new_me = _.cloneDeep(expr);
new_me.sub_filter_b = new_b;
onChange(new_me);
}
return (
<>
<Box className={classes.logic_op_outer}>
<Box className={classes.logic_op_sbs}>
<Box>
<Box className={classes.logic_op_subexpr}>
<FilterExpressionControl expr={expr.sub_filter_a} />
<FilterExpressionControl expr={expr.sub_filter_a} onChange={handleAChanged} />
</Box>
</Box>
<Box>
<Box className={classes.logic_op_subexpr}>
<FilterExpressionControl expr={expr.sub_filter_b} />
<FilterExpressionControl expr={expr.sub_filter_b} onChange={handleBChanged} />
</Box>
</Box>
</Box>
<Button
variant="outlined"
className={classes.filterexpcontrol + " " + classes.logic_op_sbs}>
className={classes.filterexpcontrol + " " + classes.logic_op_sbs}
aria-controls="simple-menu" aria-haspopup="true"
onClick={onClick}
>
{opstring}
</Button>
</Box>
@ -162,33 +285,84 @@ export function LogicalOperatorFilterExpressionControl(props) {
export function ConstFilterExpressionControl(props) {
const classes = useStyles();
const { expr } = props;
const { expr, onClick } = props;
return (
<Button variant="outlined" className={classes.filterexpcontrol}>
<Button
variant="outlined"
className={classes.filterexpcontrol}
aria-controls="simple-menu" aria-haspopup="true"
onClick={onClick}
>
{JSON.stringify(expr.constval)}
</Button>
);
}
export function FilterExpressionControl(props) {
const { expr } = props;
const { expr, onChange } = props;
const [anchorEl, setAnchorEl] = React.useState(null);
const [editDialogOpen, setEditDialogOpen] = React.useState(false);
var _ = require('lodash');
const menu_id = _.uniqueId("filter_menu_");
const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleCloseMenu = () => {
setAnchorEl(null);
};
const handleOpenEditDialog = (filter) => {
handleCloseMenu();
setEditDialogOpen(true);
}
const handleCloseEditFilterDialog = (filter) => {
setEditDialogOpen(false);
onChange(filter);
};
var filter_elem = false;
if (expr instanceof ConstFilter) {
return <ConstFilterExpressionControl {...props} />
filter_elem = <ConstFilterExpressionControl {...props} onClick={handleClick} />
} else if (expr instanceof LogicalOperatorFilter) {
return <LogicalOperatorFilterExpressionControl {...props} />
filter_elem = <LogicalOperatorFilterExpressionControl {...props} onClick={handleClick} onChange={onChange} />
} else if (expr instanceof MatchingFilter) {
return <MatchingFilterExpressionControl {...props} />
filter_elem = <MatchingFilterExpressionControl {...props} onClick={handleClick} />
} else {
throw new Error('Unsupported filter expression');
}
throw new Error('Unsupported filter expression');
return (
<>
{filter_elem}
<Menu
id={menu_id}
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleCloseMenu}
>
<MenuItem onClick={handleOpenEditDialog}>Edit</MenuItem>
</Menu>
<EditFilterExpressionDialog
onClose={handleCloseEditFilterDialog}
startingFilter={expr}
open={editDialogOpen}
/>
</>
);
}
export function FilterControl(props) {
const classes = useStyles();
const { filter, onChange, resultType, resultTypeString } = props;
const enabled = !filter_is_const_false(filter);
function handleResultToggled() {
if (enabled) {
onChange(new ConstFilter(resultType, false));
@ -198,7 +372,6 @@ export function FilterControl(props) {
}
}
const enabled = !filter_is_const_false(filter);
return (
<>
<Box className={classes.filtercontrol}>
@ -212,7 +385,7 @@ export function FilterControl(props) {
}
label={resultTypeString + ':'}
/>
<FilterExpressionControl expr={filter} />
<FilterExpressionControl expr={filter} onChange={onChange} />
</Box>
</>
);

Loading…
Cancel
Save