diff --git a/src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx b/src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx
new file mode 100644
index 0000000..3f72505
--- /dev/null
+++ b/src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx
@@ -0,0 +1,128 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2022. 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 {InputAdornment, InputLabel} from "@mui/material";
+import Box from "@mui/material/Box";
+import Grid from "@mui/material/Grid";
+import Stack from "@mui/material/Stack";
+import {styled} from "@mui/material/styles";
+import Switch from "@mui/material/Switch";
+import Typography from "@mui/material/Typography";
+import {ErrorMessage, Field, useFormikContext} from "formik";
+import React, {SyntheticEvent, useState} from "react";
+import MDBox from "qqq/components/Temporary/MDBox";
+import MDInput from "qqq/components/Temporary/MDInput";
+import MDTypography from "qqq/components/Temporary/MDTypography";
+
+const AntSwitch = styled(Switch)(({theme}) => ({
+ width: 28,
+ height: 16,
+ padding: 0,
+ display: "flex",
+ "&:active": {
+ "& .MuiSwitch-thumb": {
+ width: 15,
+ },
+ "& .MuiSwitch-switchBase.Mui-checked": {
+ transform: "translateX(9px)",
+ },
+ },
+ "& .MuiSwitch-switchBase": {
+ padding: 2,
+ "&.Mui-checked": {
+ transform: "translateX(12px)",
+ color: "#fff",
+ "& + .MuiSwitch-track": {
+ opacity: 1,
+ backgroundColor: theme.palette.mode === "dark" ? "#177ddc" : "#1890ff",
+ },
+ },
+ },
+ "& .MuiSwitch-thumb": {
+ boxShadow: "0 2px 4px 0 rgb(0 35 11 / 20%)",
+ width: 12,
+ height: 12,
+ borderRadius: 6,
+ transition: theme.transitions.create([ "width" ], {
+ duration: 200,
+ }),
+ },
+ "& .MuiSwitch-track": {
+ borderRadius: 16 / 2,
+ opacity: 1,
+ backgroundColor:
+ theme.palette.mode === "dark" ? "rgba(255,255,255,.35)" : "rgba(0,0,0,.25)",
+ boxSizing: "border-box",
+ },
+}));
+
+interface Props
+{
+ name: string;
+ label: string;
+ value: boolean;
+ isDisabled: boolean;
+}
+
+
+function QBooleanFieldSwitch({name, label, value, isDisabled}: Props) : JSX.Element
+{
+ const {setFieldValue} = useFormikContext();
+
+ const setSwitch = (event: SyntheticEvent, newValue: boolean) =>
+ {
+ if(!isDisabled)
+ {
+ setFieldValue(name, newValue);
+ event.stopPropagation();
+ }
+ }
+
+ const toggleSwitch = () =>
+ {
+ setFieldValue(name, !value);
+ }
+
+ return (
+ <>
+ {label}
+
+ setSwitch(e, false)}
+ sx={{cursor: value === false || isDisabled ? "inherit" : "pointer"}}>
+ No
+
+
+ setSwitch(e, true)}
+ sx={{cursor: value === true || isDisabled ? "inherit" : "pointer"}}>
+ Yes
+
+
+ >
+ );
+}
+
+export default QBooleanFieldSwitch
\ No newline at end of file
diff --git a/src/qqq/components/QDynamicFormField/index.tsx b/src/qqq/components/QDynamicFormField/index.tsx
index 1240fc9..f1016e6 100644
--- a/src/qqq/components/QDynamicFormField/index.tsx
+++ b/src/qqq/components/QDynamicFormField/index.tsx
@@ -19,11 +19,12 @@
* along with this program. If not, see .
*/
-import {InputAdornment} from "@mui/material";
-import Grid from "@mui/material/Grid";
+import {InputAdornment, InputLabel} from "@mui/material";
+import Box from "@mui/material/Box";
import Switch from "@mui/material/Switch";
-import {ErrorMessage, Field} from "formik";
-import React, {useState} from "react";
+import {ErrorMessage, Field, useFormikContext} from "formik";
+import React, {SyntheticEvent, useState} from "react";
+import QBooleanFieldSwitch from "qqq/components/QDynamicFormField/QBooleanFieldSwitch";
import MDBox from "qqq/components/Temporary/MDBox";
import MDInput from "qqq/components/Temporary/MDInput";
import MDTypography from "qqq/components/Temporary/MDTypography";
@@ -34,6 +35,7 @@ interface Props
label: string;
name: string;
displayFormat: string;
+ value: any;
type: string;
isEditable?: boolean;
[key: string]: any;
@@ -42,11 +44,13 @@ interface Props
}
function QDynamicFormField({
- label, name, displayFormat, bulkEditMode, bulkEditSwitchChangeHandler, type, isEditable, ...rest
+ label, name, displayFormat, value, bulkEditMode, bulkEditSwitchChangeHandler, type, isEditable, ...rest
}: Props): JSX.Element
{
- const [switchChecked, setSwitchChecked] = useState(false);
- const [isDisabled, setIsDisabled] = useState(!isEditable || bulkEditMode);
+ const [ switchChecked, setSwitchChecked ] = useState(false);
+ const [ isDisabled, setIsDisabled ] = useState(!isEditable || bulkEditMode);
+
+ const {setFieldValue} = useFormikContext();
const inputLabelProps = {};
if (type.toLowerCase().match("(date|time)"))
@@ -61,17 +65,24 @@ function QDynamicFormField({
// @ts-ignore
inputProps.startAdornment = $;
}
+ if (displayFormat && displayFormat.endsWith("%%"))
+ {
+ // @ts-ignore
+ inputProps.endAdornment = %;
+ }
- const field = () => (
- <>
-
-
-
- {!isDisabled &&
}
-
-
- >
- );
+ const field = () =>
+ (type == "checkbox" ?
+ :
+ <>
+
+
+
+ {!isDisabled &&
}
+
+
+ >
+ );
const bulkEditSwitchChanged = () =>
{
@@ -84,22 +95,24 @@ function QDynamicFormField({
if (bulkEditMode)
{
return (
-
-
-
-
-
-
+
+
+
+
+
+ {/* for checkboxes, if we put the whole thing in a label, we get bad overly aggressive toggling of the outer switch... */}
+ {(type == "checkbox" ?
+ field() :
-
-
-
+ )}
+
+
);
}
else
@@ -116,7 +129,8 @@ QDynamicFormField.defaultProps = {
bulkEditMode: false,
isEditable: true,
bulkEditSwitchChangeHandler: () =>
- {},
+ {
+ },
};
export default QDynamicFormField;
diff --git a/src/qqq/utils/QFilterUtils.ts b/src/qqq/utils/QFilterUtils.ts
index 01caccd..c51a8bc 100644
--- a/src/qqq/utils/QFilterUtils.ts
+++ b/src/qqq/utils/QFilterUtils.ts
@@ -78,7 +78,7 @@ class QFilterUtils
/*******************************************************************************
** Convert a qqq criteria operator to one expected by the grid.
*******************************************************************************/
- public static qqqCriteriaOperatorToGrid = (operator: QCriteriaOperator, fieldType: QFieldType = QFieldType.STRING): string =>
+ public static qqqCriteriaOperatorToGrid = (operator: QCriteriaOperator, fieldType: QFieldType = QFieldType.STRING, criteriaValues: any[]): string =>
{
switch (operator)
{
@@ -93,6 +93,15 @@ class QFilterUtils
case QFieldType.DATE_TIME:
return ("equals");
case QFieldType.BOOLEAN:
+ if (criteriaValues && criteriaValues[0] === true)
+ {
+ return "isTrue";
+ }
+ else if (criteriaValues && criteriaValues[0] === false)
+ {
+ return "isFalse";
+ }
+ return "is";
case QFieldType.STRING:
case QFieldType.TEXT:
case QFieldType.HTML: