mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 05:10:45 +00:00
Initial qfmd work to support datetime query expressions from frontend
This commit is contained in:
207
src/qqq/components/query/AdvancedDateTimeFilterValues.tsx
Normal file
207
src/qqq/components/query/AdvancedDateTimeFilterValues.tsx
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {NowWithOffsetExpression, NowWithOffsetOperator, NowWithOffsetUnit} from "@kingsrook/qqq-frontend-core/lib/model/query/NowWithOffsetExpression";
|
||||||
|
import {FormControl, FormControlLabel, Radio, RadioGroup, Select} from "@mui/material";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
|
import Card from "@mui/material/Card";
|
||||||
|
import Grid from "@mui/material/Grid";
|
||||||
|
import Icon from "@mui/material/Icon";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
import Modal from "@mui/material/Modal";
|
||||||
|
import {SelectChangeEvent} from "@mui/material/Select/Select";
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import React, {ReactNode, useState} from "react";
|
||||||
|
import {QCancelButton, QSaveButton} from "qqq/components/buttons/DefaultButtons";
|
||||||
|
|
||||||
|
|
||||||
|
interface Props
|
||||||
|
{
|
||||||
|
type: "date" | "datetime";
|
||||||
|
expression: any;
|
||||||
|
onSave: (expression: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvancedDateTimeFilterValues.defaultProps = {};
|
||||||
|
|
||||||
|
function AdvancedDateTimeFilterValues({type, expression, onSave}: Props): JSX.Element
|
||||||
|
{
|
||||||
|
const [originalExpression, setOriginalExpression] = useState(JSON.stringify(expression));
|
||||||
|
|
||||||
|
const [expressionType, setExpressionType] = useState(expression?.type ?? "NowWithOffset")
|
||||||
|
|
||||||
|
const [amount, setAmount] = useState(expression?.amount ?? 1)
|
||||||
|
const [timeUnit, setTimeUnit] = useState(expression?.timeUnit ?? "DAYS" as NowWithOffsetUnit);
|
||||||
|
const [operator, setOperator] = useState(expression?.operator ?? "MINUS" as NowWithOffsetOperator);
|
||||||
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if the expression (prop) has changed, re-set the state variables based on it //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(JSON.stringify(expression) !== originalExpression)
|
||||||
|
{
|
||||||
|
setExpressionType(expression?.type ?? "NowWithOffset")
|
||||||
|
setAmount(expression?.amount ?? 1)
|
||||||
|
setTimeUnit(expression?.timeUnit ?? "DAYS")
|
||||||
|
setOperator(expression?.operator ?? "MINUS")
|
||||||
|
setOriginalExpression(JSON.stringify(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
const openDialog = () =>
|
||||||
|
{
|
||||||
|
setIsOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSaveClicked = () =>
|
||||||
|
{
|
||||||
|
switch(expressionType)
|
||||||
|
{
|
||||||
|
case "NowWithOffset":
|
||||||
|
{
|
||||||
|
const expression = new NowWithOffsetExpression()
|
||||||
|
expression.operator = operator;
|
||||||
|
expression.amount = amount;
|
||||||
|
expression.timeUnit = timeUnit;
|
||||||
|
onSave(expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const close = () =>
|
||||||
|
{
|
||||||
|
setIsOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleExpressionTypeChange(e: React.ChangeEvent<HTMLInputElement>)
|
||||||
|
{
|
||||||
|
setExpressionType(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAmountChange(event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>)
|
||||||
|
{
|
||||||
|
setAmount(parseInt(event.target.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTimeUnitChange(event: SelectChangeEvent<NowWithOffsetUnit>, child: ReactNode)
|
||||||
|
{
|
||||||
|
// @ts-ignore
|
||||||
|
setTimeUnit(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOperatorChange(event: SelectChangeEvent<NowWithOffsetOperator>, child: ReactNode)
|
||||||
|
{
|
||||||
|
// @ts-ignore
|
||||||
|
setOperator(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const mainCardStyles: any = {};
|
||||||
|
mainCardStyles.width = "600px";
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// for the time units, have them end in an 's' if the amount is plural //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
const tuS = (amount == 1 ? "" : "s");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Tooltip title={`Define a more advanced ${type == "date" ? "date" : "date-time"} condition`}>
|
||||||
|
<Icon onClick={openDialog} fontSize="small" color="info" sx={{mx: 0.25, cursor: "pointer"}}>settings</Icon>
|
||||||
|
</Tooltip>
|
||||||
|
{
|
||||||
|
isOpen &&
|
||||||
|
(
|
||||||
|
<Modal open={isOpen} className="AdvancedDateTimeFilterValues">
|
||||||
|
<Box sx={{position: "absolute", overflowY: "auto", width: "100%"}}>
|
||||||
|
<Box py={3} justifyContent="center" sx={{display: "flex", mt: 8}}>
|
||||||
|
<Card sx={mainCardStyles}>
|
||||||
|
<Box p={4} pb={2}>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item pr={3} xs={12} lg={12}>
|
||||||
|
<Typography variant="h5">Advanced Date Filter Condition</Typography>
|
||||||
|
<Typography sx={{display: "flex", lineHeight: "1.7", textTransform: "revert"}} variant="button">
|
||||||
|
Select the type of expression you want for your condition.<br />
|
||||||
|
Then enter values to express your condition.
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
<RadioGroup name="expressionType" value={expressionType} onChange={handleExpressionTypeChange}>
|
||||||
|
|
||||||
|
<Box px={4} pb={4}>
|
||||||
|
<FormControlLabel value={"NowWithOffset"} control={<Radio size="small" />} label="Relative Expression" />
|
||||||
|
<Box pl={4}>
|
||||||
|
<FormControl variant="standard" sx={{verticalAlign: "bottom", width: "30%"}}>
|
||||||
|
<TextField
|
||||||
|
variant="standard"
|
||||||
|
type="number"
|
||||||
|
inputProps={{min: 0}}
|
||||||
|
autoComplete="off"
|
||||||
|
value={amount}
|
||||||
|
onChange={(event) => handleAmountChange(event)}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
<FormControl variant="standard" sx={{verticalAlign: "bottom", width: "30%"}}>
|
||||||
|
<Select value={timeUnit} disabled={false} onChange={handleTimeUnitChange} label="Unit">
|
||||||
|
{type == "datetime" && <MenuItem value="SECONDS">Second{tuS}</MenuItem>}
|
||||||
|
{type == "datetime" && <MenuItem value="MINUTES">Minute{tuS}</MenuItem>}
|
||||||
|
{type == "datetime" && <MenuItem value="HOURS">Hour{tuS}</MenuItem>}
|
||||||
|
<MenuItem value="DAYS">Day{tuS}</MenuItem>
|
||||||
|
<MenuItem value="WEEKS">Week{tuS}</MenuItem>
|
||||||
|
<MenuItem value="MONTHS">Month{tuS}</MenuItem>
|
||||||
|
<MenuItem value="YEARS">Year{tuS}</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
<FormControl variant="standard" sx={{verticalAlign: "bottom", width: "40%"}}>
|
||||||
|
<Select value={operator} disabled={false} onChange={handleOperatorChange}>
|
||||||
|
<MenuItem value="MINUS">Ago (in the past)</MenuItem>
|
||||||
|
<MenuItem value="PLUS">From now (in the future)</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
<Box p={3} pt={0}>
|
||||||
|
<Grid container pl={1} pr={1} justifyContent="right" alignItems="stretch" sx={{display: "flex-inline "}}>
|
||||||
|
<QCancelButton onClickHandler={close} iconName="cancel" disabled={false} />
|
||||||
|
<QSaveButton onClickHandler={handleSaveClicked} label="Apply" disabled={false} />
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdvancedDateTimeFilterValues;
|
@ -159,7 +159,9 @@ export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria,
|
|||||||
operatorOptions.push({label: "equals", value: QCriteriaOperator.EQUALS, valueMode: ValueMode.SINGLE_DATE});
|
operatorOptions.push({label: "equals", value: QCriteriaOperator.EQUALS, valueMode: ValueMode.SINGLE_DATE});
|
||||||
operatorOptions.push({label: "does not equal", value: QCriteriaOperator.NOT_EQUALS_OR_IS_NULL, valueMode: ValueMode.SINGLE_DATE});
|
operatorOptions.push({label: "does not equal", value: QCriteriaOperator.NOT_EQUALS_OR_IS_NULL, valueMode: ValueMode.SINGLE_DATE});
|
||||||
operatorOptions.push({label: "is after", value: QCriteriaOperator.GREATER_THAN, valueMode: ValueMode.SINGLE_DATE});
|
operatorOptions.push({label: "is after", value: QCriteriaOperator.GREATER_THAN, valueMode: ValueMode.SINGLE_DATE});
|
||||||
|
operatorOptions.push({label: "is on or after", value: QCriteriaOperator.GREATER_THAN_OR_EQUALS, valueMode: ValueMode.SINGLE_DATE});
|
||||||
operatorOptions.push({label: "is before", value: QCriteriaOperator.LESS_THAN, valueMode: ValueMode.SINGLE_DATE});
|
operatorOptions.push({label: "is before", value: QCriteriaOperator.LESS_THAN, valueMode: ValueMode.SINGLE_DATE});
|
||||||
|
operatorOptions.push({label: "is on or before", value: QCriteriaOperator.LESS_THAN_OR_EQUALS, valueMode: ValueMode.SINGLE_DATE});
|
||||||
operatorOptions.push({label: "is empty", value: QCriteriaOperator.IS_BLANK, valueMode: ValueMode.NONE});
|
operatorOptions.push({label: "is empty", value: QCriteriaOperator.IS_BLANK, valueMode: ValueMode.NONE});
|
||||||
operatorOptions.push({label: "is not empty", value: QCriteriaOperator.IS_NOT_BLANK, valueMode: ValueMode.NONE});
|
operatorOptions.push({label: "is not empty", value: QCriteriaOperator.IS_NOT_BLANK, valueMode: ValueMode.NONE});
|
||||||
//? operatorOptions.push({label: "is between", value: QCriteriaOperator.BETWEEN});
|
//? operatorOptions.push({label: "is between", value: QCriteriaOperator.BETWEEN});
|
||||||
@ -171,9 +173,9 @@ export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria,
|
|||||||
operatorOptions.push({label: "equals", value: QCriteriaOperator.EQUALS, valueMode: ValueMode.SINGLE_DATE_TIME});
|
operatorOptions.push({label: "equals", value: QCriteriaOperator.EQUALS, valueMode: ValueMode.SINGLE_DATE_TIME});
|
||||||
operatorOptions.push({label: "does not equal", value: QCriteriaOperator.NOT_EQUALS_OR_IS_NULL, valueMode: ValueMode.SINGLE_DATE_TIME});
|
operatorOptions.push({label: "does not equal", value: QCriteriaOperator.NOT_EQUALS_OR_IS_NULL, valueMode: ValueMode.SINGLE_DATE_TIME});
|
||||||
operatorOptions.push({label: "is after", value: QCriteriaOperator.GREATER_THAN, valueMode: ValueMode.SINGLE_DATE_TIME});
|
operatorOptions.push({label: "is after", value: QCriteriaOperator.GREATER_THAN, valueMode: ValueMode.SINGLE_DATE_TIME});
|
||||||
operatorOptions.push({label: "is on or after", value: QCriteriaOperator.GREATER_THAN_OR_EQUALS, valueMode: ValueMode.SINGLE_DATE_TIME});
|
operatorOptions.push({label: "is at or after", value: QCriteriaOperator.GREATER_THAN_OR_EQUALS, valueMode: ValueMode.SINGLE_DATE_TIME});
|
||||||
operatorOptions.push({label: "is before", value: QCriteriaOperator.LESS_THAN, valueMode: ValueMode.SINGLE_DATE_TIME});
|
operatorOptions.push({label: "is before", value: QCriteriaOperator.LESS_THAN, valueMode: ValueMode.SINGLE_DATE_TIME});
|
||||||
operatorOptions.push({label: "is on or before", value: QCriteriaOperator.LESS_THAN_OR_EQUALS, valueMode: ValueMode.SINGLE_DATE_TIME});
|
operatorOptions.push({label: "is at or before", value: QCriteriaOperator.LESS_THAN_OR_EQUALS, valueMode: ValueMode.SINGLE_DATE_TIME});
|
||||||
operatorOptions.push({label: "is empty", value: QCriteriaOperator.IS_BLANK, valueMode: ValueMode.NONE});
|
operatorOptions.push({label: "is empty", value: QCriteriaOperator.IS_BLANK, valueMode: ValueMode.NONE});
|
||||||
operatorOptions.push({label: "is not empty", value: QCriteriaOperator.IS_NOT_BLANK, valueMode: ValueMode.NONE});
|
operatorOptions.push({label: "is not empty", value: QCriteriaOperator.IS_NOT_BLANK, valueMode: ValueMode.NONE});
|
||||||
//? operatorOptions.push({label: "is between", value: QCriteriaOperator.BETWEEN});
|
//? operatorOptions.push({label: "is between", value: QCriteriaOperator.BETWEEN});
|
||||||
@ -335,8 +337,24 @@ export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria,
|
|||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
// event handler for value field (of all types) //
|
// event handler for value field (of all types) //
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
const handleValueChange = (event: React.ChangeEvent | SyntheticEvent, valueIndex: number | "all" = 0, newValue?: any) =>
|
const handleValueChange = (event: React.ChangeEvent | SyntheticEvent, valueIndex: number | "all" = 0, newValue?: any, newExpression?: any) =>
|
||||||
{
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if an expression was passed in - put it on the criteria, removing the values. //
|
||||||
|
// else - if no expression - make sure criteria.expression is null, and do the various values logics //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(newExpression)
|
||||||
|
{
|
||||||
|
criteria.expression = newExpression;
|
||||||
|
criteria.values = null;
|
||||||
|
updateCriteria(criteria, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
criteria.expression = null;
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const value = newValue !== undefined ? newValue : event ? event.target.value : null;
|
const value = newValue !== undefined ? newValue : event ? event.target.value : null;
|
||||||
|
|
||||||
@ -447,6 +465,12 @@ export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria,
|
|||||||
// don't need to look at values //
|
// don't need to look at values //
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
}
|
}
|
||||||
|
else if (criteria.expression)
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
// if there's an expression - let's assume it's valid //
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
}
|
||||||
else if(operatorSelectedValue.valueMode == ValueMode.DOUBLE)
|
else if(operatorSelectedValue.valueMode == ValueMode.DOUBLE)
|
||||||
{
|
{
|
||||||
if(criteria.values.length < 2)
|
if(criteria.values.length < 2)
|
||||||
@ -533,7 +557,7 @@ export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria,
|
|||||||
criteria={{id: id, ...criteria}}
|
criteria={{id: id, ...criteria}}
|
||||||
field={field}
|
field={field}
|
||||||
table={fieldTable}
|
table={fieldTable}
|
||||||
valueChangeHandler={(event, valueIndex, newValue) => handleValueChange(event, valueIndex, newValue)}
|
valueChangeHandler={(event, valueIndex, newValue, newExpression) => handleValueChange(event, valueIndex, newValue, newExpression)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box display="inline-block" pl={0.5} pr={1}>
|
<Box display="inline-block" pl={0.5} pr={1}>
|
||||||
|
@ -23,14 +23,21 @@
|
|||||||
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
||||||
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
||||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||||
|
import {NowWithOffsetExpression, NowWithOffsetOperator, NowWithOffsetUnit} from "@kingsrook/qqq-frontend-core/lib/model/query/NowWithOffsetExpression";
|
||||||
|
import {ThisOrLastPeriodExpression, ThisOrLastPeriodOperator, ThisOrLastPeriodUnit} from "@kingsrook/qqq-frontend-core/lib/model/query/ThisOrLastPeriodExpression";
|
||||||
import Autocomplete from "@mui/material/Autocomplete";
|
import Autocomplete from "@mui/material/Autocomplete";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Icon from "@mui/material/Icon";
|
import Icon from "@mui/material/Icon";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import InputAdornment from "@mui/material/InputAdornment/InputAdornment";
|
import InputAdornment from "@mui/material/InputAdornment/InputAdornment";
|
||||||
|
import Menu from "@mui/material/Menu";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
import Select, {SelectChangeEvent} from "@mui/material/Select/Select";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import React, {SyntheticEvent, useReducer} from "react";
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
|
import React, {ReactNode, SyntheticEvent, useReducer, useState} from "react";
|
||||||
import DynamicSelect from "qqq/components/forms/DynamicSelect";
|
import DynamicSelect from "qqq/components/forms/DynamicSelect";
|
||||||
|
import AdvancedDateTimeFilterValues from "qqq/components/query/AdvancedDateTimeFilterValues";
|
||||||
import {QFilterCriteriaWithId} from "qqq/components/query/CustomFilterPanel";
|
import {QFilterCriteriaWithId} from "qqq/components/query/CustomFilterPanel";
|
||||||
import FilterCriteriaPaster from "qqq/components/query/FilterCriteriaPaster";
|
import FilterCriteriaPaster from "qqq/components/query/FilterCriteriaPaster";
|
||||||
import {OperatorOption, ValueMode} from "qqq/components/query/FilterCriteriaRow";
|
import {OperatorOption, ValueMode} from "qqq/components/query/FilterCriteriaRow";
|
||||||
@ -42,7 +49,7 @@ interface Props
|
|||||||
criteria: QFilterCriteriaWithId;
|
criteria: QFilterCriteriaWithId;
|
||||||
field: QFieldMetaData;
|
field: QFieldMetaData;
|
||||||
table: QTableMetaData;
|
table: QTableMetaData;
|
||||||
valueChangeHandler: (event: React.ChangeEvent | SyntheticEvent, valueIndex?: number | "all", newValue?: any) => void;
|
valueChangeHandler: (event: React.ChangeEvent | SyntheticEvent, valueIndex?: number | "all", newValue?: any, newExpression?: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterCriteriaRowValues.defaultProps = {
|
FilterCriteriaRowValues.defaultProps = {
|
||||||
@ -50,6 +57,8 @@ FilterCriteriaRowValues.defaultProps = {
|
|||||||
|
|
||||||
function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueChangeHandler}: Props): JSX.Element
|
function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueChangeHandler}: Props): JSX.Element
|
||||||
{
|
{
|
||||||
|
const [relativeDateTimeMenuAnchorElement, setRelativeDateTimeMenuAnchorElement] = useState(null);
|
||||||
|
|
||||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||||
|
|
||||||
if (!operatorOption)
|
if (!operatorOption)
|
||||||
@ -122,6 +131,35 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
|
|||||||
/>;
|
/>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const makeDateTimeExpressionTextField = (value: string, valueIndex: number = 0, label = "Value", idPrefix = "value-") =>
|
||||||
|
{
|
||||||
|
const clearValue = (event: React.MouseEvent<HTMLAnchorElement> | React.MouseEvent<HTMLButtonElement>, index: number) =>
|
||||||
|
{
|
||||||
|
valueChangeHandler(event, index, "");
|
||||||
|
forceUpdate()
|
||||||
|
document.getElementById(`${idPrefix}${criteria.id}`).focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputProps: any = {};
|
||||||
|
inputProps.endAdornment = (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton sx={{visibility: value ? "visible" : "hidden"}} onClick={(event) => clearValue(event, valueIndex)}>
|
||||||
|
<Icon>close</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
);
|
||||||
|
|
||||||
|
return <TextField
|
||||||
|
id={`${idPrefix}${criteria.id}`}
|
||||||
|
label={label}
|
||||||
|
variant="standard"
|
||||||
|
autoComplete="off"
|
||||||
|
InputProps={{readOnly: true, unselectable: "off", ...inputProps}}
|
||||||
|
value={value}
|
||||||
|
fullWidth
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
function saveNewPasterValues(newValues: any[])
|
function saveNewPasterValues(newValues: any[])
|
||||||
{
|
{
|
||||||
if (criteria.values)
|
if (criteria.values)
|
||||||
@ -145,6 +183,47 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
|
|||||||
forceUpdate();
|
forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openRelativeDateTimeMenu = (event: React.MouseEvent<HTMLElement>) =>
|
||||||
|
{
|
||||||
|
setRelativeDateTimeMenuAnchorElement(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeRelativeDateTimeMenu = () =>
|
||||||
|
{
|
||||||
|
setRelativeDateTimeMenuAnchorElement(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setExpressionNowWithOffset = (operator: NowWithOffsetOperator, amount: number, timeUnit: NowWithOffsetUnit) =>
|
||||||
|
{
|
||||||
|
const expression = new NowWithOffsetExpression()
|
||||||
|
expression.operator = operator;
|
||||||
|
expression.amount = amount;
|
||||||
|
expression.timeUnit = timeUnit;
|
||||||
|
|
||||||
|
saveNewDateTimeExpression(expression);
|
||||||
|
|
||||||
|
closeRelativeDateTimeMenu();
|
||||||
|
};
|
||||||
|
|
||||||
|
const setExpressionThisOrLastPeriod = (operator: ThisOrLastPeriodOperator, timeUnit: ThisOrLastPeriodUnit) =>
|
||||||
|
{
|
||||||
|
const expression = new ThisOrLastPeriodExpression()
|
||||||
|
expression.operator = operator;
|
||||||
|
expression.timeUnit = timeUnit;
|
||||||
|
|
||||||
|
saveNewDateTimeExpression(expression);
|
||||||
|
|
||||||
|
closeRelativeDateTimeMenu();
|
||||||
|
};
|
||||||
|
|
||||||
|
function saveNewDateTimeExpression(expression: any)
|
||||||
|
{
|
||||||
|
criteria.expression = expression;
|
||||||
|
criteria.values = null;
|
||||||
|
valueChangeHandler(null, null, null, expression);
|
||||||
|
forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
switch (operatorOption.valueMode)
|
switch (operatorOption.valueMode)
|
||||||
{
|
{
|
||||||
case ValueMode.NONE:
|
case ValueMode.NONE:
|
||||||
@ -152,9 +231,87 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
|
|||||||
case ValueMode.SINGLE:
|
case ValueMode.SINGLE:
|
||||||
return makeTextField();
|
return makeTextField();
|
||||||
case ValueMode.SINGLE_DATE:
|
case ValueMode.SINGLE_DATE:
|
||||||
return makeTextField();
|
return <Box display="flex" alignItems="flex-end">
|
||||||
|
{
|
||||||
|
criteria.expression == null && makeTextField()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
criteria.expression != null && makeDateTimeExpressionTextField(criteria.expression.toString())
|
||||||
|
}
|
||||||
|
<Box>
|
||||||
|
<Tooltip title="Choose a common relative date-time expression" placement="top">
|
||||||
|
<Icon fontSize="small" color="info" sx={{mx: 0.25, cursor: "pointer"}} onClick={openRelativeDateTimeMenu}>event_upcoming</Icon>
|
||||||
|
</Tooltip>
|
||||||
|
<Menu
|
||||||
|
open={relativeDateTimeMenuAnchorElement}
|
||||||
|
anchorEl={relativeDateTimeMenuAnchorElement}
|
||||||
|
transformOrigin={{horizontal: "center", vertical: "top"}}
|
||||||
|
onClose={closeRelativeDateTimeMenu}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 1, "DAYS")}>1 day ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "DAYS")}>today</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "DAYS")}>yesterday</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 7, "DAYS")}>7 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "WEEKS")}>start of this week</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "WEEKS")}>start of last week</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 14, "DAYS")}>14 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 30, "DAYS")}>30 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "MONTHS")}>start of this month</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "MONTHS")}>start of last month</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 90, "DAYS")}>90 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 180, "DAYS")}>180 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 1, "YEARS")}>1 year ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "YEARS")}>start of this year</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "YEARS")}>start of last year</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<AdvancedDateTimeFilterValues type={"date"} expression={criteria.expression} onSave={(expression: any) => saveNewDateTimeExpression(expression)} />
|
||||||
|
</Box>
|
||||||
|
</Box>;
|
||||||
case ValueMode.SINGLE_DATE_TIME:
|
case ValueMode.SINGLE_DATE_TIME:
|
||||||
return makeTextField();
|
return <Box display="flex" alignItems="flex-end">
|
||||||
|
{
|
||||||
|
criteria.expression == null && makeTextField()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
criteria.expression != null && makeDateTimeExpressionTextField(criteria.expression.toString())
|
||||||
|
}
|
||||||
|
<Box>
|
||||||
|
<Tooltip title="Choose a common relative date-time expression" placement="top">
|
||||||
|
<Icon fontSize="small" color="info" sx={{mx: 0.25, cursor: "pointer"}} onClick={openRelativeDateTimeMenu}>event_upcoming</Icon>
|
||||||
|
</Tooltip>
|
||||||
|
<Menu
|
||||||
|
open={relativeDateTimeMenuAnchorElement}
|
||||||
|
anchorEl={relativeDateTimeMenuAnchorElement}
|
||||||
|
transformOrigin={{horizontal: "center", vertical: "top"}}
|
||||||
|
onClose={closeRelativeDateTimeMenu}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 1, "HOURS")}>1 hour ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "HOURS")}>start of this hour</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "HOURS")}>start of last hour</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 12, "HOURS")}>12 hours ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 24, "HOURS")}>24 hours ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "DAYS")}>start of today</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "DAYS")}>start of yesterday</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 7, "DAYS")}>7 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "WEEKS")}>start of this week</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "WEEKS")}>start of last week</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 14, "DAYS")}>14 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 30, "DAYS")}>30 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "MONTHS")}>start of this month</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "MONTHS")}>start of last month</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 90, "DAYS")}>90 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 180, "DAYS")}>180 days ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionNowWithOffset("MINUS", 1, "YEARS")}>1 year ago</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("THIS", "YEARS")}>start of this year</MenuItem>
|
||||||
|
<MenuItem onClick={() => setExpressionThisOrLastPeriod("LAST", "YEARS")}>start of last year</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<AdvancedDateTimeFilterValues type={"datetime"} expression={criteria.expression} onSave={(expression: any) => saveNewDateTimeExpression(expression)} />
|
||||||
|
</Box>
|
||||||
|
</Box>;
|
||||||
case ValueMode.DOUBLE:
|
case ValueMode.DOUBLE:
|
||||||
return <Box>
|
return <Box>
|
||||||
<Box width="50%" display="inline-block">
|
<Box width="50%" display="inline-block">
|
||||||
|
@ -446,22 +446,34 @@ input[type="search"]::-webkit-search-results-decoration { display: none; }
|
|||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix something in AND/OR dropdown in filters */
|
/* make down-arrow appear in select boxes */
|
||||||
.customFilterPanel .booleanOperatorColumn .MuiSvgIcon-root
|
.customFilterPanel .booleanOperatorColumn .MuiSvgIcon-root,
|
||||||
|
.AdvancedDateTimeFilterValues .MuiSvgIcon-root
|
||||||
{
|
{
|
||||||
display: inline-block !important;
|
display: inline-block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adjust bottom of AND/OR dropdown in filters */
|
/* adjust vertical padding in filter selects */
|
||||||
.customFilterPanel .booleanOperatorColumn .MuiInputBase-formControl
|
.customFilterPanel .booleanOperatorColumn .MuiInputBase-formControl .MuiSelect-select,
|
||||||
|
.AdvancedDateTimeFilterValues .MuiInputBase-formControl .MuiSelect-select
|
||||||
{
|
{
|
||||||
padding-bottom: calc(0.25rem + 1px);
|
padding-bottom: calc(0.25rem + 1px) !important;
|
||||||
|
padding-top: calc(0.25rem + 1px) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adjust down-arrow in AND/OR dropdown in filters */
|
.customFilterPanel .filterValuesColumn .MuiInputBase-inputAdornedEnd
|
||||||
.customFilterPanel .booleanOperatorColumn .MuiSelect-iconStandard
|
|
||||||
{
|
{
|
||||||
top: calc(50% - 0.75rem);
|
padding-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customFilterPanel .filterValuesColumn .MuiInputAdornment-positionEnd button
|
||||||
|
{
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customFilterPanel .filterValuesColumn .MuiSelect-iconStandard
|
||||||
|
{
|
||||||
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* change tags in any-of value fields to not be black bg with white text */
|
/* change tags in any-of value fields to not be black bg with white text */
|
||||||
|
@ -23,10 +23,12 @@ import {QController} from "@kingsrook/qqq-frontend-core/lib/controllers/QControl
|
|||||||
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
||||||
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
||||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||||
|
import {NowWithOffsetExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/NowWithOffsetExpression";
|
||||||
import {QCriteriaOperator} from "@kingsrook/qqq-frontend-core/lib/model/query/QCriteriaOperator";
|
import {QCriteriaOperator} from "@kingsrook/qqq-frontend-core/lib/model/query/QCriteriaOperator";
|
||||||
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
|
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
|
||||||
import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy";
|
import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy";
|
||||||
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
|
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
|
||||||
|
import {ThisOrLastPeriodExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/ThisOrLastPeriodExpression";
|
||||||
import {GridFilterItem, GridFilterModel, GridLinkOperator, GridSortItem} from "@mui/x-data-grid-pro";
|
import {GridFilterItem, GridFilterModel, GridLinkOperator, GridSortItem} from "@mui/x-data-grid-pro";
|
||||||
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
||||||
|
|
||||||
@ -285,6 +287,11 @@ class FilterUtils
|
|||||||
return (param);
|
return (param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FilterUtils.gridCriteriaValueToExpression(param))
|
||||||
|
{
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
let rs = [];
|
let rs = [];
|
||||||
for (let i = 0; i < param.length; i++)
|
for (let i = 0; i < param.length; i++)
|
||||||
{
|
{
|
||||||
@ -330,8 +337,13 @@ class FilterUtils
|
|||||||
** Convert a filter field's value from the style that qqq uses, to the style that
|
** Convert a filter field's value from the style that qqq uses, to the style that
|
||||||
** the grid uses.
|
** the grid uses.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static qqqCriteriaValuesToGrid = (operator: QCriteriaOperator, values: any[], field: QFieldMetaData): any | any[] =>
|
public static qqqCriteriaValuesToGrid = (operator: QCriteriaOperator, values: any[], expression: any, field: QFieldMetaData): any | any[] =>
|
||||||
{
|
{
|
||||||
|
if(expression)
|
||||||
|
{
|
||||||
|
return (expression);
|
||||||
|
}
|
||||||
|
|
||||||
const fieldType = field.type;
|
const fieldType = field.type;
|
||||||
if (operator === QCriteriaOperator.IS_BLANK || operator === QCriteriaOperator.IS_NOT_BLANK)
|
if (operator === QCriteriaOperator.IS_BLANK || operator === QCriteriaOperator.IS_NOT_BLANK)
|
||||||
{
|
{
|
||||||
@ -342,7 +354,7 @@ class FilterUtils
|
|||||||
return (values);
|
return (values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (values.length > 0)
|
if (values && values.length > 0)
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// make sure dates are formatted for the grid the way it expects - not the way we pass it in. //
|
// make sure dates are formatted for the grid the way it expects - not the way we pass it in. //
|
||||||
@ -353,7 +365,7 @@ class FilterUtils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (values[0]);
|
return (values ? values[0] : "");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -432,6 +444,7 @@ class FilterUtils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo - use expressions here!!
|
||||||
if (field && field.type == "DATE_TIME" && !values)
|
if (field && field.type == "DATE_TIME" && !values)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -538,7 +551,7 @@ class FilterUtils
|
|||||||
defaultFilter.items.push({
|
defaultFilter.items.push({
|
||||||
columnField: criteria.fieldName,
|
columnField: criteria.fieldName,
|
||||||
operatorValue: FilterUtils.qqqCriteriaOperatorToGrid(criteria.operator, field, values),
|
operatorValue: FilterUtils.qqqCriteriaOperatorToGrid(criteria.operator, field, values),
|
||||||
value: FilterUtils.qqqCriteriaValuesToGrid(criteria.operator, values, field),
|
value: FilterUtils.qqqCriteriaValuesToGrid(criteria.operator, values, criteria.expression, field),
|
||||||
id: id++, // not sure what this id is!!
|
id: id++, // not sure what this id is!!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -595,6 +608,18 @@ class FilterUtils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(defaultFilter && defaultFilter.items && defaultFilter.items.length)
|
||||||
|
{
|
||||||
|
defaultFilter.items.forEach((item) =>
|
||||||
|
{
|
||||||
|
const expression = this.gridCriteriaValueToExpression(item.value)
|
||||||
|
if(expression)
|
||||||
|
{
|
||||||
|
item.value = expression;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return ({filter: defaultFilter, sort: defaultSort});
|
return ({filter: defaultFilter, sort: defaultSort});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +637,7 @@ class FilterUtils
|
|||||||
const [field, fieldTable] = FilterUtils.getField(tableMetaData, criteria.fieldName);
|
const [field, fieldTable] = FilterUtils.getField(tableMetaData, criteria.fieldName);
|
||||||
if (field)
|
if (field)
|
||||||
{
|
{
|
||||||
gridItems.push({columnField: criteria.fieldName, id: i, operatorValue: FilterUtils.qqqCriteriaOperatorToGrid(criteria.operator, field, criteria.values), value: FilterUtils.qqqCriteriaValuesToGrid(criteria.operator, criteria.values, field)});
|
gridItems.push({columnField: criteria.fieldName, id: i, operatorValue: FilterUtils.qqqCriteriaOperatorToGrid(criteria.operator, field, criteria.values), value: FilterUtils.qqqCriteriaValuesToGrid(criteria.operator, criteria.values, criteria.expression, field)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,7 +736,13 @@ class FilterUtils
|
|||||||
const fieldMetadata = tableMetaData?.fields.get(item.columnField);
|
const fieldMetadata = tableMetaData?.fields.get(item.columnField);
|
||||||
const operator = FilterUtils.gridCriteriaOperatorToQQQ(item.operatorValue);
|
const operator = FilterUtils.gridCriteriaOperatorToQQQ(item.operatorValue);
|
||||||
const values = FilterUtils.gridCriteriaValueToQQQ(operator, item.value, item.operatorValue, fieldMetadata);
|
const values = FilterUtils.gridCriteriaValueToQQQ(operator, item.value, item.operatorValue, fieldMetadata);
|
||||||
qFilter.addCriteria(new QFilterCriteria(item.columnField, operator, values));
|
let criteria = new QFilterCriteria(item.columnField, operator, values);
|
||||||
|
const expression = FilterUtils.gridCriteriaValueToExpression(item.value);
|
||||||
|
if(expression)
|
||||||
|
{
|
||||||
|
criteria.expression = expression;
|
||||||
|
}
|
||||||
|
qFilter.addCriteria(criteria);
|
||||||
foundFilter = true;
|
foundFilter = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -729,6 +760,29 @@ class FilterUtils
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private static gridCriteriaValueToExpression(value: any)
|
||||||
|
{
|
||||||
|
if (value.length)
|
||||||
|
{
|
||||||
|
value = value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.type && value.type == "NowWithOffset")
|
||||||
|
{
|
||||||
|
return (new NowWithOffsetExpression(value));
|
||||||
|
}
|
||||||
|
else if (value.type && value.type == "ThisOrLastPeriod")
|
||||||
|
{
|
||||||
|
return (new ThisOrLastPeriodExpression(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** edit the input filter object, replacing any values which have {id,label} attributes
|
** edit the input filter object, replacing any values which have {id,label} attributes
|
||||||
** to instead just have the id part.
|
** to instead just have the id part.
|
||||||
|
Reference in New Issue
Block a user