diff --git a/package.json b/package.json
index cea87a5..4d4a2c9 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"@auth0/auth0-react": "1.10.2",
"@emotion/react": "11.7.1",
"@emotion/styled": "11.6.0",
- "@kingsrook/qqq-frontend-core": "1.0.96",
+ "@kingsrook/qqq-frontend-core": "1.0.98",
"@mui/icons-material": "5.4.1",
"@mui/material": "5.11.1",
"@mui/styles": "5.11.1",
diff --git a/src/qqq/components/query/AssignFilterVariable.tsx b/src/qqq/components/query/AssignFilterVariable.tsx
new file mode 100644
index 0000000..642f157
--- /dev/null
+++ b/src/qqq/components/query/AssignFilterVariable.tsx
@@ -0,0 +1,66 @@
+/*
+ * 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 {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
+import {FilterVariableExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/FilterVariableExpression";
+import Box from "@mui/material/Box";
+import Icon from "@mui/material/Icon";
+import Tooltip from "@mui/material/Tooltip";
+import CriteriaDateField from "qqq/components/query/CriteriaDateField";
+import React, {SyntheticEvent, useState} from "react";
+
+
+export type Expression = FilterVariableExpression;
+
+
+interface AssignFilterButtonProps
+{
+ valueIndex: number;
+ field: QFieldMetaData;
+ valueChangeHandler: (event: React.ChangeEvent | SyntheticEvent, valueIndex?: number | "all", newValue?: any) => void;
+}
+
+CriteriaDateField.defaultProps = {
+ valueIndex: 0,
+ label: "Value",
+ idPrefix: "value-"
+};
+
+export default function AssignFilterVariable({valueIndex, field, valueChangeHandler}: AssignFilterButtonProps): JSX.Element
+{
+ const [isValueAVariable, setIsValueAVariable] = useState(false);
+
+ const handleVariableButtonOnClick = () =>
+ {
+ setIsValueAVariable(!isValueAVariable);
+ const expression = new FilterVariableExpression({fieldName: field.name, valueIndex: valueIndex});
+ valueChangeHandler(null, valueIndex, expression);
+ };
+
+ return
+
+
+ functions
+
+
+ ;
+}
+
diff --git a/src/qqq/components/query/BasicAndAdvancedQueryControls.tsx b/src/qqq/components/query/BasicAndAdvancedQueryControls.tsx
index 7c13dff..2f45a95 100644
--- a/src/qqq/components/query/BasicAndAdvancedQueryControls.tsx
+++ b/src/qqq/components/query/BasicAndAdvancedQueryControls.tsx
@@ -114,7 +114,7 @@ export function getCurrentSortIndicator(queryFilter: QQueryFilter, tableMetaData
*******************************************************************************/
const BasicAndAdvancedQueryControls = forwardRef((props: BasicAndAdvancedQueryControlsProps, ref) =>
{
- const {metaData, tableMetaData, savedViewsComponent, columnMenuComponent, quickFilterFieldNames, setQuickFilterFieldNames, setQueryFilter, queryFilter, gridApiRef, queryFilterJSON, mode, setMode} = props;
+ const {metaData, tableMetaData, savedViewsComponent, columnMenuComponent, quickFilterFieldNames, setQuickFilterFieldNames, setQueryFilter, queryFilter, gridApiRef, queryFilterJSON, mode, setMode, queryScreenUsage} = props;
/////////////////////
// state variables //
@@ -682,6 +682,7 @@ const BasicAndAdvancedQueryControls = forwardRef((props: BasicAndAdvancedQueryCo
criteriaParam={getQuickCriteriaParam(fieldName)}
fieldMetaData={field}
defaultOperator={defaultOperator}
+ queryScreenUsage={queryScreenUsage}
handleRemoveQuickFilterField={null} />);
})
}
@@ -701,6 +702,7 @@ const BasicAndAdvancedQueryControls = forwardRef((props: BasicAndAdvancedQueryCo
criteriaParam={getQuickCriteriaParam(fieldName)}
fieldMetaData={field}
defaultOperator={defaultOperator}
+ queryScreenUsage={queryScreenUsage}
handleRemoveQuickFilterField={handleRemoveQuickFilterField} />);
})
}
diff --git a/src/qqq/components/query/CriteriaDateField.tsx b/src/qqq/components/query/CriteriaDateField.tsx
index 7040c5d..1c61f5d 100644
--- a/src/qqq/components/query/CriteriaDateField.tsx
+++ b/src/qqq/components/query/CriteriaDateField.tsx
@@ -21,6 +21,7 @@
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
+import {FilterVariableExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/FilterVariableExpression";
import {NowExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/NowExpression";
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";
@@ -34,14 +35,14 @@ import MenuItem from "@mui/material/MenuItem";
import {styled} from "@mui/material/styles";
import TextField from "@mui/material/TextField";
import Tooltip, {tooltipClasses, TooltipProps} from "@mui/material/Tooltip";
-import React, {SyntheticEvent, useEffect, useReducer, useState} from "react";
import AdvancedDateTimeFilterValues from "qqq/components/query/AdvancedDateTimeFilterValues";
import {QFilterCriteriaWithId} from "qqq/components/query/CustomFilterPanel";
import {EvaluatedExpression} from "qqq/components/query/EvaluatedExpression";
import {makeTextField} from "qqq/components/query/FilterCriteriaRowValues";
+import React, {SyntheticEvent, useReducer, useState} from "react";
-export type Expression = NowWithOffsetExpression | ThisOrLastPeriodExpression | NowExpression;
+export type Expression = NowWithOffsetExpression | ThisOrLastPeriodExpression | NowExpression | FilterVariableExpression;
interface CriteriaDateFieldProps
@@ -52,6 +53,7 @@ interface CriteriaDateFieldProps
field: QFieldMetaData;
criteria: QFilterCriteriaWithId;
valueChangeHandler: (event: React.ChangeEvent | SyntheticEvent, valueIndex?: number | "all", newValue?: any) => void;
+ allowVariables?: boolean;
}
CriteriaDateField.defaultProps = {
@@ -60,19 +62,30 @@ CriteriaDateField.defaultProps = {
idPrefix: "value-"
};
-export default function CriteriaDateField({valueIndex, label, idPrefix, field, criteria, valueChangeHandler}: CriteriaDateFieldProps): JSX.Element
+export const NoWrapTooltip = styled(({className, children, ...props}: TooltipProps) => (
+ {children}
+))({
+ [`& .${tooltipClasses.tooltip}`]: {
+ whiteSpace: "nowrap"
+ },
+});
+
+export default function CriteriaDateField({valueIndex, label, idPrefix, field, criteria, valueChangeHandler, allowVariables}: CriteriaDateFieldProps): JSX.Element
{
+ const [relativeDateTimeOpen, setRelativeDateTimeOpen] = useState(false);
const [relativeDateTimeMenuAnchorElement, setRelativeDateTimeMenuAnchorElement] = useState(null);
- const [forceAdvancedDateTimeDialogOpen, setForceAdvancedDateTimeDialogOpen] = useState(false)
+ const [forceAdvancedDateTimeDialogOpen, setForceAdvancedDateTimeDialogOpen] = useState(false);
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const openRelativeDateTimeMenu = (event: React.MouseEvent) =>
{
+ setRelativeDateTimeOpen(true);
setRelativeDateTimeMenuAnchorElement(event.currentTarget);
};
const closeRelativeDateTimeMenu = () =>
{
+ setRelativeDateTimeOpen(false);
setRelativeDateTimeMenuAnchorElement(null);
};
@@ -137,20 +150,12 @@ export default function CriteriaDateField({valueIndex, label, idPrefix, field, c
const isExpression = criteria.values && criteria.values[valueIndex] && criteria.values[valueIndex].type;
const currentExpression = isExpression ? criteria.values[valueIndex] : null;
- const NoWrapTooltip = styled(({className, children, ...props}: TooltipProps) => (
- {children}
- ))({
- [`& .${tooltipClasses.tooltip}`]: {
- whiteSpace: "nowrap"
- },
- });
-
const tooltipMenuItemFromExpression = (valueIndex: number, tooltipPlacement: "left" | "right", expression: Expression) =>
{
let startOfPrefix = "";
- if(expression.type == "ThisOrLastPeriod")
+ if (expression.type == "ThisOrLastPeriod")
{
- if(field.type == QFieldType.DATE_TIME || expression.timeUnit != "DAYS")
+ if (field.type == QFieldType.DATE_TIME || expression.timeUnit != "DAYS")
{
startOfPrefix = "start of ";
}
@@ -194,14 +199,14 @@ export default function CriteriaDateField({valueIndex, label, idPrefix, field, c
return
{
isExpression ? makeDateTimeExpressionTextField(criteria.values[valueIndex], valueIndex, label, idPrefix)
- : makeTextField(field, criteria, valueChangeHandler, valueIndex, label, idPrefix)
+ : makeTextField(field, criteria, valueChangeHandler, valueIndex, label, idPrefix, allowVariables)
}
date_range
;
case ValueMode.SINGLE_DATE_TIME:
- return ;
+ return ;
case ValueMode.DOUBLE_DATE_TIME:
return
@@ -192,10 +243,10 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
case ValueMode.DOUBLE:
return
- {makeTextField(field, criteria, valueChangeHandler, 0, "From", "from-")}
+ {makeTextField(field, criteria, valueChangeHandler, 0, "From", "from-", allowVariables)}
- {makeTextField(field, criteria, valueChangeHandler, 1, "To", "to-")}
+ {makeTextField(field, criteria, valueChangeHandler, 1, "To", "to-", allowVariables)}
;
case ValueMode.MULTI:
@@ -276,4 +327,4 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
return (
);
}
-export default FilterCriteriaRowValues;
\ No newline at end of file
+export default FilterCriteriaRowValues;
diff --git a/src/qqq/components/query/QuickFilter.tsx b/src/qqq/components/query/QuickFilter.tsx
index 3a3362b..9de8049 100644
--- a/src/qqq/components/query/QuickFilter.tsx
+++ b/src/qqq/components/query/QuickFilter.tsx
@@ -30,14 +30,15 @@ import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Menu from "@mui/material/Menu";
import TextField from "@mui/material/TextField";
-import React, {SyntheticEvent, useContext, useReducer, useState} from "react";
import QContext from "QContext";
import {QFilterCriteriaWithId} from "qqq/components/query/CustomFilterPanel";
import {getDefaultCriteriaValue, getOperatorOptions, getValueModeRequiredCount, OperatorOption, validateCriteria} from "qqq/components/query/FilterCriteriaRow";
import FilterCriteriaRowValues from "qqq/components/query/FilterCriteriaRowValues";
import XIcon from "qqq/components/query/XIcon";
+import {QueryScreenUsage} from "qqq/pages/records/query/RecordQuery";
import FilterUtils from "qqq/utils/qqq/FilterUtils";
import TableUtils from "qqq/utils/qqq/TableUtils";
+import React, {SyntheticEvent, useContext, useReducer, useState} from "react";
export type CriteriaParamType = QFilterCriteriaWithId | null | "tooComplex";
@@ -50,6 +51,7 @@ interface QuickFilterProps
updateCriteria: (newCriteria: QFilterCriteria, needDebounce: boolean, doRemoveCriteria: boolean) => void;
defaultOperator?: QCriteriaOperator;
handleRemoveQuickFilterField?: (fieldName: string) => void;
+ queryScreenUsage?: QueryScreenUsage;
}
QuickFilter.defaultProps =
@@ -71,7 +73,7 @@ export const quickFilterButtonStyles = {
minHeight: "auto",
padding: "0.375rem 0.625rem", whiteSpace: "nowrap",
marginBottom: "0.5rem"
-}
+};
/*******************************************************************************
** Test if a CriteriaParamType represents an actual query criteria - or, if it's
@@ -89,11 +91,11 @@ const criteriaParamIsCriteria = (param: CriteriaParamType): boolean =>
*******************************************************************************/
const doesOperatorOptionEqualCriteria = (operatorOption: OperatorOption, criteria: QFilterCriteriaWithId): boolean =>
{
- if(operatorOption.value == criteria.operator)
+ if (operatorOption.value == criteria.operator)
{
- if(operatorOption.implicitValues)
+ if (operatorOption.implicitValues)
{
- if(JSON.stringify(operatorOption.implicitValues) == JSON.stringify(criteria.values))
+ if (JSON.stringify(operatorOption.implicitValues) == JSON.stringify(criteria.values))
{
return (true);
}
@@ -107,7 +109,7 @@ const doesOperatorOptionEqualCriteria = (operatorOption: OperatorOption, criteri
}
return (false);
-}
+};
/*******************************************************************************
@@ -117,29 +119,29 @@ const doesOperatorOptionEqualCriteria = (operatorOption: OperatorOption, criteri
*******************************************************************************/
const getOperatorSelectedValue = (operatorOptions: OperatorOption[], criteria: QFilterCriteriaWithId, defaultOperator: QCriteriaOperator): OperatorOption =>
{
- if(criteria)
+ if (criteria)
{
const filteredOptions = operatorOptions.filter(o => doesOperatorOptionEqualCriteria(o, criteria));
- if(filteredOptions.length > 0)
+ if (filteredOptions.length > 0)
{
return (filteredOptions[0]);
}
}
const filteredOptions = operatorOptions.filter(o => o.value == defaultOperator);
- if(filteredOptions.length > 0)
+ if (filteredOptions.length > 0)
{
return (filteredOptions[0]);
}
return (null);
-}
+};
/*******************************************************************************
** Component to render a QuickFilter - that is - a button, with a Menu under it,
** with Operator and Value controls.
*******************************************************************************/
-export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData, criteriaParam, updateCriteria, defaultOperator, handleRemoveQuickFilterField}: QuickFilterProps): JSX.Element
+export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData, criteriaParam, updateCriteria, defaultOperator, handleRemoveQuickFilterField, queryScreenUsage}: QuickFilterProps): JSX.Element
{
const operatorOptions = fieldMetaData ? getOperatorOptions(tableMetaData, fullFieldName) : [];
const [_, tableForField] = TableUtils.getFieldAndTable(tableMetaData, fullFieldName);
@@ -190,7 +192,7 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (criteriaParamIsCriteria(criteriaParam) && JSON.stringify(criteriaParam) !== JSON.stringify(criteria))
{
- if(isOpen)
+ if (isOpen)
{
////////////////////////////////////////////////////////////////////////////////
// this was firing too-often for case where: there was a criteria originally //
@@ -217,12 +219,12 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
*******************************************************************************/
const criteriaNeedsReset = (): boolean =>
{
- if(criteria != null && criteriaParam == null)
+ if (criteria != null && criteriaParam == null)
{
const defaultOperatorOption = operatorOptions.filter(o => o.value == defaultOperator)[0];
- if(criteria.operator !== defaultOperatorOption?.value || JSON.stringify(criteria.values) !== JSON.stringify(getDefaultCriteriaValue()))
+ if (criteria.operator !== defaultOperatorOption?.value || JSON.stringify(criteria.values) !== JSON.stringify(getDefaultCriteriaValue()))
{
- if(isOpen)
+ if (isOpen)
{
//////////////////////////////////////////////////////////////////////////////////
// this was firing too-often for case where: there was no criteria originally, //
@@ -237,7 +239,7 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
}
return (false);
- }
+ };
/*******************************************************************************
** Construct a new criteria object - resetting the values tied to the operator
@@ -251,8 +253,8 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
setOperatorSelectedValue(operatorOption);
setOperatorInputValue(operatorOption?.label);
setCriteria(criteria);
- return(criteria);
- }
+ return (criteria);
+ };
/*******************************************************************************
** event handler to open the menu in response to the button being clicked.
@@ -266,7 +268,7 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
{
const element = document.getElementById("value-" + criteria.id);
element?.focus();
- })
+ });
};
/*******************************************************************************
@@ -304,15 +306,15 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
// we've seen cases where switching operators can sometimes put a null in as the first value... //
// that just causes a bad time (e.g., null pointers in Autocomplete), so, get rid of that. //
//////////////////////////////////////////////////////////////////////////////////////////////////
- if(criteria.values && criteria.values.length == 1 && criteria.values[0] == null)
+ if (criteria.values && criteria.values.length == 1 && criteria.values[0] == null)
{
criteria.values = [];
}
- if(newValue.valueMode && !newValue.implicitValues)
+ if (newValue.valueMode && !newValue.implicitValues)
{
const requiredValueCount = getValueModeRequiredCount(newValue.valueMode);
- if(requiredValueCount != null && criteria.values.length > requiredValueCount)
+ if (requiredValueCount != null && criteria.values.length > requiredValueCount)
{
criteria.values.splice(requiredValueCount);
}
@@ -345,6 +347,7 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
// @ts-ignore
const value = newValue !== undefined ? newValue : event ? event.target.value : null;
+ console.log("IN HERE");
if (!criteria.values)
{
criteria.values = [];
@@ -376,13 +379,13 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
*******************************************************************************/
const resetCriteria = (e: React.MouseEvent) =>
{
- if(criteriaIsValid)
+ if (criteriaIsValid)
{
e.stopPropagation();
const newCriteria = makeNewCriteria();
updateCriteria(newCriteria, false, true);
}
- }
+ };
/*******************************************************************************
** event handler for clicking the (x) icon that turns off this quick filter field.
@@ -390,17 +393,17 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
*******************************************************************************/
const handleTurningOffQuickFilterField = () =>
{
- closeMenu()
- if(handleRemoveQuickFilterField)
+ closeMenu();
+ if (handleRemoveQuickFilterField)
{
handleRemoveQuickFilterField(criteria?.fieldName);
}
- }
+ };
////////////////////////////////////////////////////////////////////////////////////
// if no field was input (e.g., record-query is still loading), return null early //
////////////////////////////////////////////////////////////////////////////////////
- if(!fieldMetaData)
+ if (!fieldMetaData)
{
return (null);
}
@@ -410,10 +413,10 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
// from the last selected one, then set the state vars that control that autocomplete //
//////////////////////////////////////////////////////////////////////////////////////////
const maybeNewOperatorSelectedValue = getOperatorSelectedValue(operatorOptions, criteria, defaultOperator);
- if(JSON.stringify(maybeNewOperatorSelectedValue) !== JSON.stringify(operatorSelectedValue))
+ if (JSON.stringify(maybeNewOperatorSelectedValue) !== JSON.stringify(operatorSelectedValue))
{
- setOperatorSelectedValue(maybeNewOperatorSelectedValue)
- setOperatorInputValue(maybeNewOperatorSelectedValue?.label)
+ setOperatorSelectedValue(maybeNewOperatorSelectedValue);
+ setOperatorInputValue(maybeNewOperatorSelectedValue?.label);
}
/////////////////////////////////////////////////////////////////////////////////////
@@ -431,7 +434,7 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
const tooltipEnterDelay = 500;
let buttonAdditionalStyles: any = {};
- let buttonContent = {tableForField?.name != tableMetaData.name ? `${tableForField.label}: ` : ""}{fieldMetaData.label}
+ let buttonContent = {tableForField?.name != tableMetaData.name ? `${tableForField.label}: ` : ""}{fieldMetaData.label};
let buttonClassName = "filterNotActive";
if (criteriaIsValid)
{
@@ -446,9 +449,9 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
// don't show the Equals or In operators //
///////////////////////////////////////////
let operatorString = (<>{operatorSelectedValue.label} >);
- if(operatorSelectedValue.value == QCriteriaOperator.EQUALS || operatorSelectedValue.value == QCriteriaOperator.IN)
+ if (operatorSelectedValue.value == QCriteriaOperator.EQUALS || operatorSelectedValue.value == QCriteriaOperator.IN)
{
- operatorString = (<>>)
+ operatorString = (<>>);
}
buttonContent = (<>{buttonContent}: {operatorString}{valuesString}>);
@@ -491,7 +494,7 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
const xClicked = (e: React.MouseEvent) =>
{
e.stopPropagation();
- if(criteriaIsValid)
+ if (criteriaIsValid)
{
resetCriteria(e);
}
@@ -499,12 +502,12 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
{
handleTurningOffQuickFilterField();
}
- }
+ };
//////////////////////////////
// return the button & menu //
//////////////////////////////
- const widthAndMaxWidth = fieldMetaData?.type == QFieldType.DATE_TIME ? 275 : 250
+ const widthAndMaxWidth = (fieldMetaData?.type == QFieldType.DATE_TIME) ? 295 : 250;
return (
<>
{button}
@@ -541,6 +544,7 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
{
onClickCallback();
- }
+ };
return (
@@ -236,7 +234,6 @@ export function HeaderToggleComponent({label, getValue, onClickCallback, disable
}
-
/*******************************************************************************
**
*******************************************************************************/
@@ -698,7 +695,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element
);
let sublabelElement = (
-
+
{props.widgetData?.sublabel}
@@ -785,7 +782,7 @@ function Widget(props: React.PropsWithChildren): JSX.Element
}
{localLabelAdditionalElementsLeft}
-
+
{
hasPermission && props.widgetData?.sublabel && (sublabelElement)
}
diff --git a/src/qqq/components/widgets/misc/PivotTableSetupWidget.tsx b/src/qqq/components/widgets/misc/PivotTableSetupWidget.tsx
index 7b243e4..9c22a98 100644
--- a/src/qqq/components/widgets/misc/PivotTableSetupWidget.tsx
+++ b/src/qqq/components/widgets/misc/PivotTableSetupWidget.tsx
@@ -280,7 +280,7 @@ export default function PivotTableSetupWidget({isEditable, widgetMetaData, recor
}
modalPivotTableDefinition[rowsOrColumns].push(new PivotTableGroupBy());
- validateForm()
+ validateForm();
forceUpdate();
}
@@ -292,7 +292,7 @@ export default function PivotTableSetupWidget({isEditable, widgetMetaData, recor
{
updateUsedGroupByFieldNames(modalPivotTableDefinition);
updateUsedValueFieldNames(modalPivotTableDefinition);
- validateForm()
+ validateForm();
forceUpdate();
}
@@ -308,7 +308,7 @@ export default function PivotTableSetupWidget({isEditable, widgetMetaData, recor
}
modalPivotTableDefinition.values.push(new PivotTableValue());
- validateForm()
+ validateForm();
forceUpdate();
}
@@ -319,7 +319,7 @@ export default function PivotTableSetupWidget({isEditable, widgetMetaData, recor
function removeValue(index: number)
{
modalPivotTableDefinition.values.splice(index, 1);
- validateForm()
+ validateForm();
forceUpdate();
}
@@ -503,7 +503,7 @@ export default function PivotTableSetupWidget({isEditable, widgetMetaData, recor
const labelAdditionalElementsRight: JSX.Element[] = [];
if (isEditable)
{
- labelAdditionalElementsRight.push( enabled} onClickCallback={toggleEnabled} />);
+ labelAdditionalElementsRight.push( enabled} onClickCallback={toggleEnabled} />);
}
@@ -659,7 +659,7 @@ export default function PivotTableSetupWidget({isEditable, widgetMetaData, recor
// if this isn't a call from the on-submit handler, and we haven't previously attempted a submit, then return w/o setting any alerts //
// this is like a version of considering "touched"... //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- if(!submitting && !attemptedSubmit)
+ if (!submitting && !attemptedSubmit)
{
return;
}
@@ -703,7 +703,7 @@ export default function PivotTableSetupWidget({isEditable, widgetMetaData, recor
// now they've fixed 'em - so go back to a 'clean' state - so if they add more //
// boxes, they won't immediately show errors, until a re-submit //
////////////////////////////////////////////////////////////////////////////////////
- if(attemptedSubmit)
+ if (attemptedSubmit)
{
setAttemptedSubmit(false);
}
diff --git a/src/qqq/components/widgets/misc/ReportSetupWidget.tsx b/src/qqq/components/widgets/misc/ReportSetupWidget.tsx
index 3466088..05ebfa2 100644
--- a/src/qqq/components/widgets/misc/ReportSetupWidget.tsx
+++ b/src/qqq/components/widgets/misc/ReportSetupWidget.tsx
@@ -46,8 +46,8 @@ interface ReportSetupWidgetProps
{
isEditable: boolean;
widgetMetaData: QWidgetMetaData;
- recordValues: {[name: string]: any};
- onSaveCallback?: (values: {[name: string]: any}) => void;
+ recordValues: { [name: string]: any };
+ onSaveCallback?: (values: { [name: string]: any }) => void;
}
ReportSetupWidget.defaultProps = {
@@ -103,14 +103,14 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
/////////////////////////////
let queryFilter = recordValues["queryFilterJson"] && JSON.parse(recordValues["queryFilterJson"]) as QQueryFilter;
let usingDefaultEmptyFilter = false;
- if(!queryFilter)
+ if (!queryFilter)
{
queryFilter = new QQueryFilter();
usingDefaultEmptyFilter = true;
}
let columns: QQueryColumns = null;
- if(recordValues["columnsJson"])
+ if (recordValues["columnsJson"])
{
columns = QQueryColumns.buildFromJSON(recordValues["columnsJson"]);
}
@@ -124,12 +124,12 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
{
(async () =>
{
- const tableMetaData = await qController.loadTableMetaData(recordValues["tableName"])
+ const tableMetaData = await qController.loadTableMetaData(recordValues["tableName"]);
setTableMetaData(tableMetaData);
const queryFilterForFrontend = Object.assign({}, queryFilter);
- await FilterUtils.cleanupValuesInFilerFromQueryString(qController, tableMetaData, queryFilterForFrontend)
- setFrontendQueryFilter(queryFilterForFrontend)
+ await FilterUtils.cleanupValuesInFilerFromQueryString(qController, tableMetaData, queryFilterForFrontend);
+ setFrontendQueryFilter(queryFilterForFrontend);
})();
}
}, [recordValues]);
@@ -140,7 +140,7 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
*******************************************************************************/
function openEditor()
{
- if(recordValues["tableName"])
+ if (recordValues["tableName"])
{
setModalOpen(true);
}
@@ -152,7 +152,7 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
*******************************************************************************/
function saveClicked()
{
- if(!onSaveCallback)
+ if (!onSaveCallback)
{
console.log("onSaveCallback was not defined");
return;
@@ -181,7 +181,7 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
*******************************************************************************/
function closeEditor(event?: {}, reason?: "backdropClick" | "escapeKeyDown")
{
- if(reason == "backdropClick" || reason == "escapeKeyDown")
+ if (reason == "backdropClick" || reason == "escapeKeyDown")
{
return;
}
@@ -195,9 +195,9 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
*******************************************************************************/
function renderColumn(column: Column): JSX.Element
{
- const [field, table] = FilterUtils.getField(tableMetaData, column.name)
+ const [field, table] = FilterUtils.getField(tableMetaData, column.name);
- if(!column || !column.isVisible || column.name == "__check__" || !field)
+ if (!column || !column.isVisible || column.name == "__check__" || !field)
{
return ();
}
@@ -215,9 +215,9 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
*******************************************************************************/
function mayShowQueryPreview(): boolean
{
- if(tableMetaData)
+ if (tableMetaData)
{
- if(frontendQueryFilter?.criteria?.length > 0 || frontendQueryFilter?.subFilters?.length > 0)
+ if (frontendQueryFilter?.criteria?.length > 0 || frontendQueryFilter?.subFilters?.length > 0)
{
return (true);
}
@@ -231,11 +231,11 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
*******************************************************************************/
function mayShowColumnsPreview(): boolean
{
- if(tableMetaData)
+ if (tableMetaData)
{
- for(let i = 0; i)
+ labelAdditionalElementsRight.push();
}
@@ -316,7 +316,7 @@ export default function ReportSetupWidget({isEditable, widgetMetaData, recordVal
{
mayShowColumnsPreview() &&
- columns.columns.map((column, i) => {renderColumn(column)})
+ columns.columns.map((column, i) => {renderColumn(column)})
}
{
!mayShowColumnsPreview() &&
diff --git a/src/qqq/pages/records/query/RecordQuery.tsx b/src/qqq/pages/records/query/RecordQuery.tsx
index 0b3fd57..25609ec 100644
--- a/src/qqq/pages/records/query/RecordQuery.tsx
+++ b/src/qqq/pages/records/query/RecordQuery.tsx
@@ -109,7 +109,7 @@ const qController = Client.getInstance();
*******************************************************************************/
const getLoadingScreen = (isModal: boolean) =>
{
- if(isModal)
+ if (isModal)
{
return ( );
}
@@ -151,7 +151,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
*******************************************************************************/
function localStorageSet(key: string, value: string)
{
- if(mayWriteLocalStorage)
+ if (mayWriteLocalStorage)
{
localStorage.setItem(key, value);
}
@@ -163,7 +163,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
*******************************************************************************/
function localStorageRemove(key: string)
{
- if(mayWriteLocalStorage)
+ if (mayWriteLocalStorage)
{
localStorage.removeItem(key);
}
@@ -176,7 +176,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
{
return view;
}
- }
+ };
});
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -256,7 +256,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
defaultView.mode = defaultMode;
}
- if(firstRender)
+ if (firstRender)
{
/////////////////////////////////////////////////////////////////////////
// allow a caller to send in an initial filter & set of columns. //
@@ -408,7 +408,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
//////////////////////////////////////////////////////////////////
// we use our own header - so clear out the context page header //
//////////////////////////////////////////////////////////////////
- if(!isModal)
+ if (!isModal)
{
setPageHeader(null);
}
@@ -486,7 +486,6 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
};
-
/*******************************************************************************
**
*******************************************************************************/
@@ -711,7 +710,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
{
if (localStorage.getItem(currentSavedViewLocalStorageKey))
{
- if(usage == "queryScreen")
+ if (usage == "queryScreen")
{
currentSavedViewId = Number.parseInt(localStorage.getItem(currentSavedViewLocalStorageKey));
navigate(`${metaData.getTablePathByName(tableName)}/savedView/${currentSavedViewId}`);
@@ -750,13 +749,13 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
const viewForLocalStorage: RecordQueryView = JSON.parse(viewAsJSON);
if (viewForLocalStorage?.queryFilter?.criteria?.length > 0)
{
- FilterUtils.stripAwayIncompleteCriteria(viewForLocalStorage.queryFilter)
+ FilterUtils.stripAwayIncompleteCriteria(viewForLocalStorage.queryFilter);
}
localStorageSet(viewLocalStorageKey, JSON.stringify(viewForLocalStorage));
}
- catch(e)
+ catch (e)
{
- console.log("Error storing view in local storage: " + e)
+ console.log("Error storing view in local storage: " + e);
}
};
@@ -939,7 +938,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
console.log(`Issuing query: ${thisQueryId}`);
if (tableMetaData.capabilities.has(Capability.TABLE_COUNT))
{
- if(clearOutCount)
+ if (clearOutCount)
{
setTotalRecords(null);
setDistinctRecords(null);
@@ -1437,7 +1436,6 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
return (selectedIds.length);
};
-
/*******************************************************************************
** get a query-string to put on the url to indicate what records are going into
** a process.
@@ -2527,7 +2525,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
{
const currentSavedViewId = Number.parseInt(localStorage.getItem(currentSavedViewLocalStorageKey));
console.log(`returning to previously active saved view ${currentSavedViewId}`);
- if(usage == "queryScreen")
+ if (usage == "queryScreen")
{
navigate(`${metaData.getTablePathByName(tableName)}/savedView/${currentSavedViewId}`);
}
@@ -2770,7 +2768,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
spaceAboveGrid += 60;
}
- if(isModal)
+ if (isModal)
{
spaceAboveGrid += 130;
}
@@ -2976,15 +2974,15 @@ const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, init
);
- if(isModal)
+ if (isModal)
{
return body;
}
return (
{body}
- )
-})
+ );
+});
RecordQuery.defaultProps = {
diff --git a/src/qqq/utils/qqq/FilterUtils.tsx b/src/qqq/utils/qqq/FilterUtils.tsx
index eaa8940..b2bbfd7 100644
--- a/src/qqq/utils/qqq/FilterUtils.tsx
+++ b/src/qqq/utils/qqq/FilterUtils.tsx
@@ -23,6 +23,7 @@ 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 {FilterVariableExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/FilterVariableExpression";
import {NowExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/NowExpression";
import {NowWithOffsetExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/NowWithOffsetExpression";
import {QCriteriaOperator} from "@kingsrook/qqq-frontend-core/lib/model/query/QCriteriaOperator";
@@ -365,7 +366,12 @@ class FilterUtils
for (let i = 0; i < maxLoops; i++)
{
const value = criteria.values[i];
- if (value.type == "NowWithOffset")
+ if (value.type == "FilterVariableExpression")
+ {
+ const expression = new FilterVariableExpression(value);
+ labels.push(expression.toString());
+ }
+ else if (value.type == "NowWithOffset")
{
const expression = new NowWithOffsetExpression(value);
labels.push(expression.toString());
@@ -657,7 +663,7 @@ class FilterUtils
filterForBackend.subFilters = subFilters;
- if(pageNumber !== undefined && rowsPerPage !== undefined)
+ if (pageNumber !== undefined && rowsPerPage !== undefined)
{
filterForBackend.skip = pageNumber * rowsPerPage;
filterForBackend.limit = rowsPerPage;