diff --git a/src/qqq/components/query/AdvancedDateTimeFilterValues.tsx b/src/qqq/components/query/AdvancedDateTimeFilterValues.tsx
new file mode 100644
index 0000000..fe08c19
--- /dev/null
+++ b/src/qqq/components/query/AdvancedDateTimeFilterValues.tsx
@@ -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 .
+ */
+
+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)
+ {
+ setExpressionType(e.target.value);
+ }
+
+ function handleAmountChange(event: React.ChangeEvent)
+ {
+ setAmount(parseInt(event.target.value));
+ }
+
+ function handleTimeUnitChange(event: SelectChangeEvent, child: ReactNode)
+ {
+ // @ts-ignore
+ setTimeUnit(event.target.value)
+ }
+
+ function handleOperatorChange(event: SelectChangeEvent, 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 (
+
+
+ settings
+
+ {
+ isOpen &&
+ (
+
+
+
+
+
+
+
+ Advanced Date Filter Condition
+
+ Select the type of expression you want for your condition.
+ Then enter values to express your condition.
+
+
+
+
+
+
+
+ } label="Relative Expression" />
+
+
+ handleAmountChange(event)}
+ fullWidth
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+
+ );
+}
+
+export default AdvancedDateTimeFilterValues;
diff --git a/src/qqq/components/query/FilterCriteriaRow.tsx b/src/qqq/components/query/FilterCriteriaRow.tsx
index 850a065..ff6dd2d 100644
--- a/src/qqq/components/query/FilterCriteriaRow.tsx
+++ b/src/qqq/components/query/FilterCriteriaRow.tsx
@@ -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: "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 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 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 not empty", value: QCriteriaOperator.IS_NOT_BLANK, valueMode: ValueMode.NONE});
//? 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: "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 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 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 not empty", value: QCriteriaOperator.IS_NOT_BLANK, valueMode: ValueMode.NONE});
//? 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) //
//////////////////////////////////////////////////
- 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
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 //
//////////////////////////////////
}
+ else if (criteria.expression)
+ {
+ ////////////////////////////////////////////////////////
+ // if there's an expression - let's assume it's valid //
+ ////////////////////////////////////////////////////////
+ }
else if(operatorSelectedValue.valueMode == ValueMode.DOUBLE)
{
if(criteria.values.length < 2)
@@ -533,7 +557,7 @@ export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria,
criteria={{id: id, ...criteria}}
field={field}
table={fieldTable}
- valueChangeHandler={(event, valueIndex, newValue) => handleValueChange(event, valueIndex, newValue)}
+ valueChangeHandler={(event, valueIndex, newValue, newExpression) => handleValueChange(event, valueIndex, newValue, newExpression)}
/>
diff --git a/src/qqq/components/query/FilterCriteriaRowValues.tsx b/src/qqq/components/query/FilterCriteriaRowValues.tsx
index ef1452b..b0a70e7 100644
--- a/src/qqq/components/query/FilterCriteriaRowValues.tsx
+++ b/src/qqq/components/query/FilterCriteriaRowValues.tsx
@@ -23,14 +23,21 @@
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
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 Box from "@mui/material/Box";
import Icon from "@mui/material/Icon";
import IconButton from "@mui/material/IconButton";
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 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 AdvancedDateTimeFilterValues from "qqq/components/query/AdvancedDateTimeFilterValues";
import {QFilterCriteriaWithId} from "qqq/components/query/CustomFilterPanel";
import FilterCriteriaPaster from "qqq/components/query/FilterCriteriaPaster";
import {OperatorOption, ValueMode} from "qqq/components/query/FilterCriteriaRow";
@@ -42,7 +49,7 @@ interface Props
criteria: QFilterCriteriaWithId;
field: QFieldMetaData;
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 = {
@@ -50,6 +57,8 @@ FilterCriteriaRowValues.defaultProps = {
function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueChangeHandler}: Props): JSX.Element
{
+ const [relativeDateTimeMenuAnchorElement, setRelativeDateTimeMenuAnchorElement] = useState(null);
+
const [, forceUpdate] = useReducer((x) => x + 1, 0);
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 | React.MouseEvent, index: number) =>
+ {
+ valueChangeHandler(event, index, "");
+ forceUpdate()
+ document.getElementById(`${idPrefix}${criteria.id}`).focus();
+ };
+
+ const inputProps: any = {};
+ inputProps.endAdornment = (
+
+ clearValue(event, valueIndex)}>
+ close
+
+
+ );
+
+ return ;
+ }
+
function saveNewPasterValues(newValues: any[])
{
if (criteria.values)
@@ -145,6 +183,47 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
forceUpdate();
}
+ const openRelativeDateTimeMenu = (event: React.MouseEvent) =>
+ {
+ 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)
{
case ValueMode.NONE:
@@ -152,9 +231,87 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
case ValueMode.SINGLE:
return makeTextField();
case ValueMode.SINGLE_DATE:
- return makeTextField();
+ return
+ {
+ criteria.expression == null && makeTextField()
+ }
+ {
+ criteria.expression != null && makeDateTimeExpressionTextField(criteria.expression.toString())
+ }
+
+
+ event_upcoming
+
+
+
+
+ saveNewDateTimeExpression(expression)} />
+
+ ;
case ValueMode.SINGLE_DATE_TIME:
- return makeTextField();
+ return
+ {
+ criteria.expression == null && makeTextField()
+ }
+ {
+ criteria.expression != null && makeDateTimeExpressionTextField(criteria.expression.toString())
+ }
+
+
+ event_upcoming
+
+
+
+
+ saveNewDateTimeExpression(expression)} />
+
+ ;
case ValueMode.DOUBLE:
return
diff --git a/src/qqq/styles/qqq-override-styles.css b/src/qqq/styles/qqq-override-styles.css
index 0b791d4..73d6aa5 100644
--- a/src/qqq/styles/qqq-override-styles.css
+++ b/src/qqq/styles/qqq-override-styles.css
@@ -446,22 +446,34 @@ input[type="search"]::-webkit-search-results-decoration { display: none; }
font-size: 14px !important;
}
-/* fix something in AND/OR dropdown in filters */
-.customFilterPanel .booleanOperatorColumn .MuiSvgIcon-root
+/* make down-arrow appear in select boxes */
+.customFilterPanel .booleanOperatorColumn .MuiSvgIcon-root,
+.AdvancedDateTimeFilterValues .MuiSvgIcon-root
{
display: inline-block !important;
}
-/* adjust bottom of AND/OR dropdown in filters */
-.customFilterPanel .booleanOperatorColumn .MuiInputBase-formControl
+/* adjust vertical padding in filter selects */
+.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 .booleanOperatorColumn .MuiSelect-iconStandard
+.customFilterPanel .filterValuesColumn .MuiInputBase-inputAdornedEnd
{
- 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 */
diff --git a/src/qqq/utils/qqq/FilterUtils.ts b/src/qqq/utils/qqq/FilterUtils.ts
index a428c2c..2c5b0dd 100644
--- a/src/qqq/utils/qqq/FilterUtils.ts
+++ b/src/qqq/utils/qqq/FilterUtils.ts
@@ -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 {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
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 {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy";
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 ValueUtils from "qqq/utils/qqq/ValueUtils";
@@ -285,6 +287,11 @@ class FilterUtils
return (param);
}
+ if (FilterUtils.gridCriteriaValueToExpression(param))
+ {
+ return (null);
+ }
+
let rs = [];
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
** 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;
if (operator === QCriteriaOperator.IS_BLANK || operator === QCriteriaOperator.IS_NOT_BLANK)
{
@@ -342,7 +354,7 @@ class FilterUtils
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. //
@@ -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)
{
try
@@ -538,7 +551,7 @@ class FilterUtils
defaultFilter.items.push({
columnField: criteria.fieldName,
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!!
});
}
@@ -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});
}
@@ -612,7 +637,7 @@ class FilterUtils
const [field, fieldTable] = FilterUtils.getField(tableMetaData, criteria.fieldName);
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 operator = FilterUtils.gridCriteriaOperatorToQQQ(item.operatorValue);
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;
});
@@ -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
** to instead just have the id part.