mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-21 22:58:43 +00:00
Compare commits
3 Commits
snapshot-f
...
snapshot-i
Author | SHA1 | Date | |
---|---|---|---|
beb0b415fa | |||
aac579232d | |||
6469d569c0 |
@ -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.104",
|
||||
"@kingsrook/qqq-frontend-core": "1.0.102",
|
||||
"@mui/icons-material": "5.4.1",
|
||||
"@mui/material": "5.11.1",
|
||||
"@mui/styles": "5.11.1",
|
||||
@ -59,7 +59,7 @@
|
||||
"build": "react-scripts build",
|
||||
"clean": "rm -rf node_modules package-lock.json lib",
|
||||
"eject": "react-scripts eject",
|
||||
"clean-and-install": "rm -rf node_modules/ && rm -rf package-lock.json && rm -rf lib/ && npm install --legacy-peer-deps && npm dedupe --force",
|
||||
"clean-and-install": "rm -rf node_modules/ && rm -rf package-lock.json && rm -rf lib/ && npm install --legacy-peer-deps",
|
||||
"npm-install": "npm install --legacy-peer-deps",
|
||||
"prepublishOnly": "tsc -p ./ --outDir lib/",
|
||||
"start": "BROWSER=none react-scripts --max-http-header-size=65535 start",
|
||||
|
@ -72,7 +72,7 @@ const CommandMenu = ({metaData}: Props) =>
|
||||
const navigate = useNavigate();
|
||||
const pathParts = location.pathname.replace(/\/+$/, "").split("/");
|
||||
|
||||
const {accentColor, tableMetaData, dotMenuOpen, setDotMenuOpen, keyboardHelpOpen, setKeyboardHelpOpen, setTableMetaData, tableProcesses, recordAnalytics} = useContext(QContext);
|
||||
const {accentColor, tableMetaData, dotMenuOpen, setDotMenuOpen, keyboardHelpOpen, setKeyboardHelpOpen, setTableMetaData, tableProcesses} = useContext(QContext);
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
@ -87,7 +87,6 @@ const CommandMenu = ({metaData}: Props) =>
|
||||
if (e.key === "." && !keyboardHelpOpen)
|
||||
{
|
||||
e.preventDefault();
|
||||
recordAnalytics({category: "globalEvents", action: "dotMenuKeyboardShortcut"});
|
||||
setDotMenuOpen(true);
|
||||
}
|
||||
else if (e.key === "?" && !dotMenuOpen)
|
||||
@ -424,20 +423,9 @@ const CommandMenu = ({metaData}: Props) =>
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// iterate over the search parts - if any don't match the corresponding value parts, then it's a non-match //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
let valueIndex = 0;
|
||||
for (let i = 0; i < searchParts.length; i++)
|
||||
{
|
||||
let foundMatch = false;
|
||||
for (; valueIndex < valueParts.length; valueIndex++)
|
||||
{
|
||||
if (valueParts[valueIndex].includes(searchParts[i]))
|
||||
{
|
||||
foundMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMatch)
|
||||
if (!valueParts[i].includes(searchParts[i]))
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
@ -19,17 +19,16 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Box, InputAdornment, InputLabel} from "@mui/material";
|
||||
import {InputAdornment, InputLabel} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import {ErrorMessage, Field, useFormikContext} from "formik";
|
||||
import DynamicFormUtils from "qqq/components/forms/DynamicFormUtils";
|
||||
import React, {useMemo, useState} from "react";
|
||||
import React, {useState} from "react";
|
||||
import AceEditor from "react-ace";
|
||||
import colors from "qqq/assets/theme/base/colors";
|
||||
import BooleanFieldSwitch from "qqq/components/forms/BooleanFieldSwitch";
|
||||
import MDInput from "qqq/components/legacy/MDInput";
|
||||
import MDTypography from "qqq/components/legacy/MDTypography";
|
||||
import {flushSync} from "react-dom";
|
||||
|
||||
// Declaring props types for FormField
|
||||
interface Props
|
||||
@ -86,51 +85,6 @@ function QDynamicFormField({
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// check the field meta data for behavior that says to do toUpperCase or toLowerCase //
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
let isToUpperCase = useMemo(() => DynamicFormUtils.isToUpperCase(formFieldObject?.fieldMetaData), [formFieldObject]);
|
||||
let isToLowerCase = useMemo(() => DynamicFormUtils.isToLowerCase(formFieldObject?.fieldMetaData), [formFieldObject]);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// if the field has a toUpperCase or toLowerCase behavior on it, then //
|
||||
// apply that rule. But also, to avoid the cursor always jumping to //
|
||||
// the end of the input, do some manipulation of the selection. //
|
||||
// See: https://giacomocerquone.com/blog/keep-input-cursor-still //
|
||||
// Note, we only want an onChange handle if we're doing one of these //
|
||||
// behaviors, (because teh flushSync is potentially slow). hence, we //
|
||||
// put the onChange in an object and assign it with a spread //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
let onChange: any = {};
|
||||
if (isToUpperCase || isToLowerCase)
|
||||
{
|
||||
onChange.onChange = (e: any) =>
|
||||
{
|
||||
const beforeStart = e.target.selectionStart;
|
||||
const beforeEnd = e.target.selectionEnd;
|
||||
|
||||
flushSync(() =>
|
||||
{
|
||||
let newValue = e.currentTarget.value;
|
||||
if (isToUpperCase)
|
||||
{
|
||||
newValue = newValue.toUpperCase();
|
||||
}
|
||||
if (isToLowerCase)
|
||||
{
|
||||
newValue = newValue.toLowerCase();
|
||||
}
|
||||
setFieldValue(name, newValue);
|
||||
});
|
||||
|
||||
const input = document.getElementById(name) as HTMLInputElement;
|
||||
if (input)
|
||||
{
|
||||
input.setSelectionRange(beforeStart, beforeEnd);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let field;
|
||||
let getsBulkEditHtmlLabel = true;
|
||||
if (type === "checkbox")
|
||||
@ -179,7 +133,7 @@ function QDynamicFormField({
|
||||
{
|
||||
field = (
|
||||
<>
|
||||
<Field {...rest} {...onChange} onWheel={handleOnWheel} name={name} type={type} as={MDInput} variant="outlined" label={label} InputLabelProps={inputLabelProps} InputProps={inputProps} fullWidth disabled={isDisabled}
|
||||
<Field {...rest} onWheel={handleOnWheel} name={name} type={type} as={MDInput} variant="outlined" label={label} InputLabelProps={inputLabelProps} InputProps={inputProps} fullWidth disabled={isDisabled}
|
||||
onKeyPress={(e: any) =>
|
||||
{
|
||||
if (e.key === "Enter")
|
||||
@ -219,8 +173,7 @@ function QDynamicFormField({
|
||||
id={`bulkEditSwitch-${name}`}
|
||||
checked={switchChecked}
|
||||
onClick={bulkEditSwitchChanged}
|
||||
sx={{
|
||||
top: "-4px",
|
||||
sx={{top: "-4px",
|
||||
"& .MuiSwitch-track": {
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
|
@ -214,7 +214,7 @@ class DynamicFormUtils
|
||||
|
||||
if (Array.isArray(disabledFields))
|
||||
{
|
||||
return (disabledFields.indexOf(fieldName) > -1);
|
||||
return (disabledFields.indexOf(fieldName) > -1)
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -222,44 +222,6 @@ class DynamicFormUtils
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* check if a field has the TO_UPPER_CASE behavior on it.
|
||||
***************************************************************************/
|
||||
public static isToUpperCase(fieldMetaData: QFieldMetaData): boolean
|
||||
{
|
||||
return this.hasBehavior(fieldMetaData, "TO_UPPER_CASE");
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* check if a field has the TO_LOWER_CASE behavior on it.
|
||||
***************************************************************************/
|
||||
public static isToLowerCase(fieldMetaData: QFieldMetaData): boolean
|
||||
{
|
||||
return this.hasBehavior(fieldMetaData, "TO_LOWER_CASE");
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* check if a field has a specific behavior name on it.
|
||||
***************************************************************************/
|
||||
private static hasBehavior(fieldMetaData: QFieldMetaData, behaviorName: string): boolean
|
||||
{
|
||||
if (fieldMetaData && fieldMetaData.behaviors)
|
||||
{
|
||||
for (let i = 0; i < fieldMetaData.behaviors.length; i++)
|
||||
{
|
||||
if (fieldMetaData.behaviors[i] == behaviorName)
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DynamicFormUtils;
|
||||
|
@ -97,7 +97,7 @@ export const getAutocompleteOutlinedStyle = (isDisabled: boolean) =>
|
||||
borderColor: inputBorderColor
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const qController = Client.getInstance();
|
||||
@ -108,13 +108,13 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
const [options, setOptions] = useState<readonly QPossibleValue[]>([]);
|
||||
const [searchTerm, setSearchTerm] = useState(null);
|
||||
const [firstRender, setFirstRender] = useState(true);
|
||||
const [otherValuesWhenResultsWereLoaded, setOtherValuesWhenResultsWereLoaded] = useState(JSON.stringify(Object.fromEntries((otherValues))));
|
||||
const [otherValuesWhenResultsWereLoaded, setOtherValuesWhenResultsWereLoaded] = useState(JSON.stringify(Object.fromEntries((otherValues))))
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(tableName && processName)
|
||||
{
|
||||
console.log("DynamicSelect - you may not provide both a tableName and a processName");
|
||||
console.log("DynamicSelect - you may not provide both a tableName and a processName")
|
||||
}
|
||||
if(tableName && !fieldName)
|
||||
{
|
||||
@ -233,7 +233,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
setOtherValuesWhenResultsWereLoaded(JSON.stringify(Object.fromEntries(otherValues)));
|
||||
})();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const inputChanged = (event: React.SyntheticEvent, value: string, reason: string) =>
|
||||
{
|
||||
@ -248,7 +248,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
const handleBlur = (x: any) =>
|
||||
{
|
||||
setSearchTerm(null);
|
||||
};
|
||||
}
|
||||
|
||||
const handleChanged = (event: React.SyntheticEvent, value: any | any[], reason: string, details?: string) =>
|
||||
{
|
||||
@ -280,7 +280,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
// get options whose text/label matches the input (e.g., not ids that match) //
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
return (options);
|
||||
};
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const renderOption = (props: Object, option: any, {selected}) =>
|
||||
@ -289,13 +289,13 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
|
||||
try
|
||||
{
|
||||
const field = tableMetaData?.fields.get(fieldName);
|
||||
const field = tableMetaData?.fields.get(fieldName)
|
||||
if(field)
|
||||
{
|
||||
const adornment = field.getAdornment(AdornmentType.CHIP);
|
||||
if(adornment)
|
||||
{
|
||||
const color = adornment.getValue("color." + option.id) ?? "default";
|
||||
const color = adornment.getValue("color." + option.id) ?? "default"
|
||||
const iconName = adornment.getValue("icon." + option.id) ?? null;
|
||||
const iconElement = iconName ? <Icon>{iconName}</Icon> : null;
|
||||
content = (<Chip label={option.label} color={color} icon={iconElement} size="small" variant="outlined" sx={{fontWeight: 500}} />);
|
||||
@ -303,8 +303,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
if(isMultiple)
|
||||
{
|
||||
@ -328,7 +327,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
{content}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const bulkEditSwitchChanged = () =>
|
||||
{
|
||||
@ -383,7 +382,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
option = option[0];
|
||||
}
|
||||
// @ts-ignore
|
||||
return option.label;
|
||||
return option.label
|
||||
}}
|
||||
options={options}
|
||||
loading={loading}
|
||||
@ -447,8 +446,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
id={`bulkEditSwitch-${fieldName}`}
|
||||
checked={switchChecked}
|
||||
onClick={bulkEditSwitchChanged}
|
||||
sx={{
|
||||
top: "-4px",
|
||||
sx={{top: "-4px",
|
||||
"& .MuiSwitch-track": {
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
@ -467,7 +465,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
else
|
||||
{
|
||||
return (
|
||||
<Box>
|
||||
<Box mb={1.5}>
|
||||
{autocomplete}
|
||||
</Box>
|
||||
);
|
||||
|
@ -396,16 +396,15 @@ function EntityForm(props: Props): JSX.Element
|
||||
// if the widget metadata specifies a table name, set form values to that so widget knows which to use //
|
||||
// (for the case when it is not being specified by a separate field in the record) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if (widgetData?.tableName)
|
||||
if (widgetMetaData?.defaultValues?.has("tableName"))
|
||||
{
|
||||
formValues["tableName"] = widgetData?.tableName;
|
||||
formValues["tableName"] = widgetMetaData?.defaultValues.get("tableName");
|
||||
}
|
||||
|
||||
return <FilterAndColumnsSetupWidget
|
||||
key={formValues["tableName"]} // todo, is this good? it was added so that editing values actually re-renders...
|
||||
isEditable={true}
|
||||
widgetMetaData={widgetMetaData}
|
||||
widgetData={widgetData}
|
||||
recordValues={formValues}
|
||||
onSaveCallback={setFormFieldValuesFromWidget}
|
||||
/>;
|
||||
|
@ -85,7 +85,7 @@ function QBreadcrumbs({icon, title, route, light}: Props): JSX.Element
|
||||
}
|
||||
|
||||
return (routeToLabel(route));
|
||||
};
|
||||
}
|
||||
|
||||
let pageTitle = branding?.appName ?? "";
|
||||
const fullRoutes: string[] = [];
|
||||
@ -94,9 +94,9 @@ function QBreadcrumbs({icon, title, route, light}: Props): JSX.Element
|
||||
{
|
||||
////////////////////////////////////////////////////////
|
||||
// avoid showing "saved view" as a breadcrumb element //
|
||||
// e.g., if at /app/table/savedView/1 //
|
||||
// e.g., if at /app/table/savedView/1 (so where i==2) //
|
||||
////////////////////////////////////////////////////////
|
||||
if (routes[i] === "savedView" && i == routes.length - 1)
|
||||
if(routes[i] === "savedView" && i == 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -19,15 +19,16 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Popper, InputAdornment, Box} from "@mui/material";
|
||||
import {Popper, InputAdornment} from "@mui/material";
|
||||
import AppBar from "@mui/material/AppBar";
|
||||
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 ListItemIcon from "@mui/material/ListItemIcon";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Toolbar from "@mui/material/Toolbar";
|
||||
import React, {useContext, useEffect, useRef, useState} from "react";
|
||||
import React, {useContext, useEffect, useState} from "react";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
import QContext from "QContext";
|
||||
import QBreadcrumbs, {routeToLabel} from "qqq/components/horseshoe/Breadcrumbs";
|
||||
@ -44,8 +45,7 @@ interface Props
|
||||
isMini?: boolean;
|
||||
}
|
||||
|
||||
interface HistoryEntry
|
||||
{
|
||||
interface HistoryEntry {
|
||||
id: number;
|
||||
path: string;
|
||||
label: string;
|
||||
@ -64,7 +64,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
const route = useLocation().pathname.split("/").slice(1);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {pageHeader, setDotMenuOpen} = useContext(QContext);
|
||||
const {pageHeader} = useContext(QContext);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@ -99,7 +99,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
const options = [] as any;
|
||||
history.entries.reverse().forEach((entry, index) =>
|
||||
options.push({label: `${entry.label} index`, id: index, key: index, path: entry.path, iconName: entry.iconName})
|
||||
);
|
||||
)
|
||||
setHistory(options);
|
||||
|
||||
// Remove event listener on cleanup
|
||||
@ -111,7 +111,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
const goToHistory = (path: string) =>
|
||||
{
|
||||
navigate(path);
|
||||
};
|
||||
}
|
||||
|
||||
function buildHistoryEntries()
|
||||
{
|
||||
@ -119,7 +119,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
const options = [] as any;
|
||||
history.entries.reverse().forEach((entry, index) =>
|
||||
options.push({label: entry.label, id: index, key: index, path: entry.path, iconName: entry.iconName})
|
||||
);
|
||||
)
|
||||
setHistory(options);
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
goToHistory(value.path);
|
||||
}
|
||||
setAutocompleteValue(null);
|
||||
};
|
||||
}
|
||||
|
||||
const CustomPopper = function (props: any)
|
||||
{
|
||||
@ -146,8 +146,8 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
{...props}
|
||||
style={{whiteSpace: "nowrap", width: "auto"}}
|
||||
placement="bottom-end"
|
||||
/>);
|
||||
};
|
||||
/>)
|
||||
}
|
||||
|
||||
const renderHistory = () =>
|
||||
{
|
||||
@ -184,7 +184,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// Styles for the navbar icons
|
||||
const iconsStyle = ({
|
||||
@ -221,7 +221,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
}
|
||||
|
||||
return (routeToLabel(route));
|
||||
};
|
||||
}
|
||||
|
||||
const breadcrumbTitle = fullPathToLabel(fullPath, route[route.length - 1]);
|
||||
|
||||
@ -242,14 +242,9 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
</Box>
|
||||
{isMini ? null : (
|
||||
<Box sx={(theme) => navbarRow(theme, {isMini})}>
|
||||
<Box mt={"-0.25rem"} pb={"0.75rem"} pr={2} mr={-2} sx={{"& *": {cursor: "pointer !important"}}}>
|
||||
<Box pr={0} mr={-2}>
|
||||
{renderHistory()}
|
||||
</Box>
|
||||
<Box mt={"-1rem"}>
|
||||
<IconButton size="small" disableRipple color="inherit" onClick={() => setDotMenuOpen(true)}>
|
||||
<Icon sx={iconsStyle} fontSize="small">search</Icon>
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Toolbar>
|
||||
|
@ -79,8 +79,6 @@ interface BasicAndAdvancedQueryControlsProps
|
||||
|
||||
queryScreenUsage: QueryScreenUsage;
|
||||
|
||||
allowVariables?: boolean;
|
||||
|
||||
mode: string;
|
||||
setMode: (mode: string) => void;
|
||||
}
|
||||
@ -678,7 +676,6 @@ const BasicAndAdvancedQueryControls = forwardRef((props: BasicAndAdvancedQueryCo
|
||||
|
||||
return (<QuickFilter
|
||||
key={fieldName}
|
||||
allowVariables={props.allowVariables}
|
||||
fullFieldName={fieldName}
|
||||
tableMetaData={tableMetaData}
|
||||
updateCriteria={updateQuickCriteria}
|
||||
@ -704,7 +701,6 @@ const BasicAndAdvancedQueryControls = forwardRef((props: BasicAndAdvancedQueryCo
|
||||
updateCriteria={updateQuickCriteria}
|
||||
criteriaParam={getQuickCriteriaParam(fieldName)}
|
||||
fieldMetaData={field}
|
||||
allowVariables={props.allowVariables}
|
||||
defaultOperator={defaultOperator}
|
||||
queryScreenUsage={queryScreenUsage}
|
||||
handleRemoveQuickFilterField={handleRemoveQuickFilterField} />);
|
||||
|
@ -179,7 +179,6 @@ export const CustomFilterPanel = forwardRef<any, GridFilterPanelProps>(
|
||||
updateCriteria={(newCriteria, needDebounce) => updateCriteria(newCriteria, index, needDebounce)}
|
||||
removeCriteria={() => removeCriteria(index)}
|
||||
updateBooleanOperator={(newValue) => updateBooleanOperator(newValue)}
|
||||
allowVariables={props.allowVariables}
|
||||
queryScreenUsage={props.queryScreenUsage}
|
||||
/>
|
||||
{/*JSON.stringify(criteria)*/}
|
||||
|
@ -199,7 +199,6 @@ interface FilterCriteriaRowProps
|
||||
removeCriteria: () => void;
|
||||
updateBooleanOperator: (newValue: string) => void;
|
||||
queryScreenUsage?: QueryScreenUsage;
|
||||
allowVariables?: boolean;
|
||||
}
|
||||
|
||||
FilterCriteriaRow.defaultProps =
|
||||
@ -268,7 +267,7 @@ export function validateCriteria(criteria: QFilterCriteria, operatorSelectedValu
|
||||
return {criteriaIsValid, criteriaStatusTooltip};
|
||||
}
|
||||
|
||||
export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria, booleanOperator, updateCriteria, removeCriteria, updateBooleanOperator, queryScreenUsage, allowVariables}: FilterCriteriaRowProps): JSX.Element
|
||||
export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria, booleanOperator, updateCriteria, removeCriteria, updateBooleanOperator, queryScreenUsage}: FilterCriteriaRowProps): JSX.Element
|
||||
{
|
||||
// console.log(`FilterCriteriaRow: criteria: ${JSON.stringify(criteria)}`);
|
||||
const [operatorSelectedValue, setOperatorSelectedValue] = useState(null as OperatorOption);
|
||||
@ -517,7 +516,6 @@ export function FilterCriteriaRow({id, index, tableMetaData, metaData, criteria,
|
||||
table={fieldTable}
|
||||
valueChangeHandler={(event, valueIndex, newValue) => handleValueChange(event, valueIndex, newValue)}
|
||||
queryScreenUsage={queryScreenUsage}
|
||||
allowVariables={allowVariables}
|
||||
/>
|
||||
</Box>
|
||||
<Box display="inline-block">
|
||||
|
@ -30,7 +30,6 @@ import Icon from "@mui/material/Icon";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import InputAdornment from "@mui/material/InputAdornment/InputAdornment";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import DynamicFormUtils from "qqq/components/forms/DynamicFormUtils";
|
||||
import DynamicSelect from "qqq/components/forms/DynamicSelect";
|
||||
import AssignFilterVariable from "qqq/components/query/AssignFilterVariable";
|
||||
import CriteriaDateField, {NoWrapTooltip} from "qqq/components/query/CriteriaDateField";
|
||||
@ -40,8 +39,7 @@ import FilterCriteriaPaster from "qqq/components/query/FilterCriteriaPaster";
|
||||
import {OperatorOption, ValueMode} from "qqq/components/query/FilterCriteriaRow";
|
||||
import {QueryScreenUsage} from "qqq/pages/records/query/RecordQuery";
|
||||
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
||||
import React, {SyntheticEvent, useReducer} from "react";
|
||||
import {flushSync} from "react-dom";
|
||||
import React, {SyntheticEvent, useReducer, useState} from "react";
|
||||
|
||||
interface Props
|
||||
{
|
||||
@ -52,7 +50,6 @@ interface Props
|
||||
valueChangeHandler: (event: React.ChangeEvent | SyntheticEvent, valueIndex?: number | "all", newValue?: any) => void;
|
||||
initiallyOpenMultiValuePvs?: boolean;
|
||||
queryScreenUsage?: QueryScreenUsage;
|
||||
allowVariables?: boolean;
|
||||
}
|
||||
|
||||
FilterCriteriaRowValues.defaultProps =
|
||||
@ -60,10 +57,6 @@ FilterCriteriaRowValues.defaultProps =
|
||||
initiallyOpenMultiValuePvs: false
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* get the type to use for an <input> from a QFieldMetaData
|
||||
***************************************************************************/
|
||||
export const getTypeForTextField = (field: QFieldMetaData): string =>
|
||||
{
|
||||
let type = "search";
|
||||
@ -84,15 +77,10 @@ export const getTypeForTextField = (field: QFieldMetaData): string =>
|
||||
return (type);
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Make an <input type=text> (actually, might be a different type, but that's
|
||||
* the gist of it), for a field.
|
||||
***************************************************************************/
|
||||
export const makeTextField = (field: QFieldMetaData, criteria: QFilterCriteriaWithId, valueChangeHandler?: (event: (React.ChangeEvent | React.SyntheticEvent), valueIndex?: (number | "all"), newValue?: any) => void, valueIndex: number = 0, label = "Value", idPrefix = "value-", allowVariables = false) =>
|
||||
{
|
||||
const isExpression = criteria.values && criteria.values[valueIndex] && criteria.values[valueIndex].type;
|
||||
const inputId = `${idPrefix}${criteria.id}`;
|
||||
|
||||
let type = getTypeForTextField(field);
|
||||
const inputLabelProps: any = {};
|
||||
|
||||
@ -107,13 +95,10 @@ export const makeTextField = (field: QFieldMetaData, criteria: QFilterCriteriaWi
|
||||
value = ValueUtils.formatDateTimeValueForForm(value);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Event handler for the clear 'x'.
|
||||
***************************************************************************/
|
||||
const clearValue = (event: React.MouseEvent<HTMLAnchorElement> | React.MouseEvent<HTMLButtonElement>, index: number) =>
|
||||
{
|
||||
valueChangeHandler(event, index, "");
|
||||
document.getElementById(inputId).focus();
|
||||
document.getElementById(`${idPrefix}${criteria.id}`).focus();
|
||||
};
|
||||
|
||||
|
||||
@ -134,10 +119,6 @@ export const makeTextField = (field: QFieldMetaData, criteria: QFilterCriteriaWi
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* make a version of the text field for when the criteria's value is set to
|
||||
* be a "variable"
|
||||
***************************************************************************/
|
||||
const makeFilterVariableTextField = (expression: FilterVariableExpression, valueIndex: number = 0, label = "Value", idPrefix = "value-") =>
|
||||
{
|
||||
const clearValue = (event: React.MouseEvent<HTMLAnchorElement> | React.MouseEvent<HTMLButtonElement>, index: number) =>
|
||||
@ -167,10 +148,6 @@ export const makeTextField = (field: QFieldMetaData, criteria: QFilterCriteriaWi
|
||||
/></NoWrapTooltip>;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// set up an 'x' icon as an end-adornment, to clear value from the field //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
const inputProps: any = {};
|
||||
inputProps.endAdornment = (
|
||||
<InputAdornment position="end">
|
||||
@ -180,64 +157,18 @@ export const makeTextField = (field: QFieldMetaData, criteria: QFilterCriteriaWi
|
||||
</InputAdornment>
|
||||
);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* onChange event handler. deals with, if the field has a to upper/lower
|
||||
* case rule on it, to apply that transform, and adjust the cursor.
|
||||
* See: https://giacomocerquone.com/blog/keep-input-cursor-still
|
||||
***************************************************************************/
|
||||
function onChange(event: any)
|
||||
{
|
||||
const beforeStart = event.target.selectionStart;
|
||||
const beforeEnd = event.target.selectionEnd;
|
||||
|
||||
let isToUpperCase = DynamicFormUtils.isToUpperCase(field);
|
||||
let isToLowerCase = DynamicFormUtils.isToLowerCase(field);
|
||||
|
||||
if (isToUpperCase || isToLowerCase)
|
||||
{
|
||||
flushSync(() =>
|
||||
{
|
||||
let newValue = event.currentTarget.value;
|
||||
|
||||
if (isToUpperCase)
|
||||
{
|
||||
newValue = newValue.toUpperCase();
|
||||
}
|
||||
if (isToLowerCase)
|
||||
{
|
||||
newValue = newValue.toLowerCase();
|
||||
}
|
||||
|
||||
event.currentTarget.value = newValue;
|
||||
});
|
||||
|
||||
const input = document.getElementById(inputId);
|
||||
if (input)
|
||||
{
|
||||
// @ts-ignore
|
||||
input.setSelectionRange(beforeStart, beforeEnd);
|
||||
}
|
||||
}
|
||||
|
||||
valueChangeHandler(event, valueIndex);
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// return the element //
|
||||
////////////////////////
|
||||
return <Box sx={{margin: 0, padding: 0, display: "flex"}}>
|
||||
{
|
||||
isExpression ? (
|
||||
makeFilterVariableTextField(criteria.values[valueIndex], valueIndex, label, idPrefix)
|
||||
) : (
|
||||
<TextField
|
||||
id={inputId}
|
||||
id={`${idPrefix}${criteria.id}`}
|
||||
label={label}
|
||||
variant="standard"
|
||||
autoComplete="off"
|
||||
type={type}
|
||||
onChange={onChange}
|
||||
onChange={(event) => valueChangeHandler(event, valueIndex)}
|
||||
onKeyDown={handleKeyDown}
|
||||
value={value}
|
||||
InputLabelProps={inputLabelProps}
|
||||
@ -256,23 +187,16 @@ export const makeTextField = (field: QFieldMetaData, criteria: QFilterCriteriaWi
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Component that is the "values" portion of a FilterCriteria Row in the
|
||||
* advanced query filter editor.
|
||||
***************************************************************************/
|
||||
function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueChangeHandler, initiallyOpenMultiValuePvs, queryScreenUsage, allowVariables}: Props): JSX.Element
|
||||
function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueChangeHandler, initiallyOpenMultiValuePvs, queryScreenUsage}: Props): JSX.Element
|
||||
{
|
||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||
const [allowVariables, setAllowVariables] = useState(queryScreenUsage == "reportSetup");
|
||||
|
||||
if (!operatorOption)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Callback for the Save button from the paste-values modal
|
||||
***************************************************************************/
|
||||
function saveNewPasterValues(newValues: any[])
|
||||
{
|
||||
if (criteria.values)
|
||||
@ -298,9 +222,6 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
|
||||
|
||||
const isExpression = criteria.values && criteria.values[0] && criteria.values[0].type;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// render different form element9s) based on operator option's "value mode" //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
switch (operatorOption.valueMode)
|
||||
{
|
||||
case ValueMode.NONE:
|
||||
@ -399,7 +320,7 @@ function FilterCriteriaRowValues({operatorOption, criteria, field, table, valueC
|
||||
initialValues = criteria.values;
|
||||
}
|
||||
}
|
||||
return <Box>
|
||||
return <Box mb={-1.5}>
|
||||
<DynamicSelect
|
||||
tableName={table.name}
|
||||
fieldName={field.name}
|
||||
|
@ -52,7 +52,6 @@ interface QuickFilterProps
|
||||
defaultOperator?: QCriteriaOperator;
|
||||
handleRemoveQuickFilterField?: (fieldName: string) => void;
|
||||
queryScreenUsage?: QueryScreenUsage;
|
||||
allowVariables?: boolean;
|
||||
}
|
||||
|
||||
QuickFilter.defaultProps =
|
||||
@ -142,7 +141,7 @@ const getOperatorSelectedValue = (operatorOptions: OperatorOption[], criteria: Q
|
||||
** 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, queryScreenUsage, allowVariables}: 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);
|
||||
@ -550,7 +549,6 @@ export default function QuickFilter({tableMetaData, fullFieldName, fieldMetaData
|
||||
criteria={criteria}
|
||||
field={fieldMetaData}
|
||||
table={tableForField}
|
||||
allowVariables={allowVariables}
|
||||
valueChangeHandler={(event, valueIndex, newValue) => handleValueChange(event, valueIndex, newValue)}
|
||||
initiallyOpenMultiValuePvs={true} // todo - maybe not?
|
||||
/>
|
||||
|
@ -599,8 +599,8 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "filterAndColumnsSetup" && (
|
||||
widgetData && widgetData[i] &&
|
||||
<FilterAndColumnsSetupWidget isEditable={false} widgetMetaData={widgetMetaData} widgetData={widgetData[i]} recordValues={convertQRecordValuesFromMapToObject(record)} onSaveCallback={() =>
|
||||
widgetData && widgetData[i] && widgetData[i].queryParams &&
|
||||
<FilterAndColumnsSetupWidget isEditable={false} widgetMetaData={widgetMetaData} recordValues={convertQRecordValuesFromMapToObject(record)} onSaveCallback={() =>
|
||||
{
|
||||
}} />
|
||||
)
|
||||
|
@ -48,7 +48,6 @@ interface FilterAndColumnsSetupWidgetProps
|
||||
{
|
||||
isEditable: boolean;
|
||||
widgetMetaData: QWidgetMetaData;
|
||||
widgetData: any;
|
||||
recordValues: { [name: string]: any };
|
||||
onSaveCallback?: (values: { [name: string]: any }) => void;
|
||||
}
|
||||
@ -83,10 +82,10 @@ const qController = Client.getInstance();
|
||||
/*******************************************************************************
|
||||
** Component for editing the main setup of a report - that is: filter & columns
|
||||
*******************************************************************************/
|
||||
export default function FilterAndColumnsSetupWidget({isEditable, widgetMetaData, widgetData, recordValues, onSaveCallback}: FilterAndColumnsSetupWidgetProps): JSX.Element
|
||||
export default function FilterAndColumnsSetupWidget({isEditable, widgetMetaData, recordValues, onSaveCallback}: FilterAndColumnsSetupWidgetProps): JSX.Element
|
||||
{
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [hideColumns, setHideColumns] = useState(widgetData?.hideColumns);
|
||||
const [hideColumns, setHideColumns] = useState(widgetMetaData?.defaultValues?.has("hideColumns") && widgetMetaData?.defaultValues?.get("hideColumns"));
|
||||
const [tableMetaData, setTableMetaData] = useState(null as QTableMetaData);
|
||||
|
||||
const [alertContent, setAlertContent] = useState(null as string);
|
||||
@ -108,7 +107,7 @@ export default function FilterAndColumnsSetupWidget({isEditable, widgetMetaData,
|
||||
let columns: QQueryColumns = null;
|
||||
let usingDefaultEmptyFilter = false;
|
||||
let queryFilter = recordValues["queryFilterJson"] && JSON.parse(recordValues["queryFilterJson"]) as QQueryFilter;
|
||||
const defaultFilterFields = widgetData?.filterDefaultFieldNames;
|
||||
const defaultFilterFields = getDefaultFilterFieldNames(widgetMetaData);
|
||||
if (!queryFilter)
|
||||
{
|
||||
queryFilter = new QQueryFilter();
|
||||
@ -154,7 +153,7 @@ export default function FilterAndColumnsSetupWidget({isEditable, widgetMetaData,
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if a default table name specified, use it, otherwise use it from the record values //
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
let tableName = widgetData?.tableName;
|
||||
let tableName = widgetMetaData?.defaultValues?.get("tableName");
|
||||
if (!tableName && recordValues["tableName"] && (tableMetaData == null || tableMetaData.name != recordValues["tableName"]))
|
||||
{
|
||||
tableName = recordValues["tableName"];
|
||||
@ -175,13 +174,27 @@ export default function FilterAndColumnsSetupWidget({isEditable, widgetMetaData,
|
||||
}, [JSON.stringify(recordValues)]);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
function getDefaultFilterFieldNames(widgetMetaData: QWidgetMetaData)
|
||||
{
|
||||
if (widgetMetaData?.defaultValues?.has("filterDefaultFieldNames"))
|
||||
{
|
||||
return (widgetMetaData.defaultValues.get("filterDefaultFieldNames").split(","));
|
||||
}
|
||||
|
||||
return ([]);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
function openEditor()
|
||||
{
|
||||
let missingRequiredFields = [] as string[];
|
||||
widgetData?.filterDefaultFieldNames?.forEach((fieldName: string) =>
|
||||
getDefaultFilterFieldNames(widgetMetaData)?.forEach((fieldName: string) =>
|
||||
{
|
||||
if (!recordValues[fieldName])
|
||||
{
|
||||
@ -417,7 +430,6 @@ export default function FilterAndColumnsSetupWidget({isEditable, widgetMetaData,
|
||||
}
|
||||
{
|
||||
tableMetaData && <RecordQuery
|
||||
allowVariables={widgetData?.allowVariables}
|
||||
ref={recordQueryRef}
|
||||
table={tableMetaData}
|
||||
usage="reportSetup"
|
||||
|
@ -33,7 +33,6 @@ import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJo
|
||||
import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
|
||||
import {QJobRunning} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobRunning";
|
||||
import {QJobStarted} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobStarted";
|
||||
import {QPossibleValue} from "@kingsrook/qqq-frontend-core/lib/model/QPossibleValue";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
|
||||
import {Alert, Box, Button, CircularProgress, Icon, TablePagination} from "@mui/material";
|
||||
@ -97,8 +96,6 @@ let formikSetFieldValueFunction = (field: string, value: any, shouldValidate?: b
|
||||
{
|
||||
};
|
||||
|
||||
const cachedPossibleValueLabels: { [fieldName: string]: { [id: string | number]: string } } = {};
|
||||
|
||||
function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, isReport, recordIds, closeModalHandler, forceReInit, overrideLabel}: Props): JSX.Element
|
||||
{
|
||||
const processNameParam = useParams().processName;
|
||||
@ -446,21 +443,8 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
{
|
||||
if (processValues[key])
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if we have a cached possible-value label for this field name (key), then set it as the PV's initialDisplayValue //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if (cachedPossibleValueLabels[key] && cachedPossibleValueLabels[key][processValues[key]])
|
||||
{
|
||||
formFields[key].possibleValueProps.initialDisplayValue = cachedPossibleValueLabels[key][processValues[key]];
|
||||
}
|
||||
else
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// else (and i don't think this should happen?) at least set something... //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
formFields[key].possibleValueProps.initialDisplayValue = processValues[key];
|
||||
}
|
||||
}
|
||||
|
||||
formFields[key].possibleValueProps.otherValues = formFields[key].possibleValueProps.otherValues ?? new Map<string, any>();
|
||||
Object.keys(formFields).forEach((otherKey) =>
|
||||
@ -881,12 +865,6 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
{
|
||||
dynamicFormFields[fieldName] = dynamicFormValue;
|
||||
initialValues[fieldName] = initialValue;
|
||||
|
||||
if (formikSetFieldValueFunction)
|
||||
{
|
||||
formikSetFieldValueFunction(fieldName, initialValue);
|
||||
}
|
||||
|
||||
formValidations[fieldName] = validation;
|
||||
};
|
||||
|
||||
@ -936,11 +914,6 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
fullFieldList.forEach((field) =>
|
||||
{
|
||||
initialValues[field.name] = processValues[field.name];
|
||||
|
||||
if (formikSetFieldValueFunction)
|
||||
{
|
||||
formikSetFieldValueFunction(field.name, processValues[field.name]);
|
||||
}
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1099,67 +1072,11 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
setRetryMillis(INITIAL_RETRY_MILLIS);
|
||||
|
||||
if (lastProcessResponse instanceof QJobComplete)
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// run an async function here, in case we need to await looking up any possible-value labels //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
(async () =>
|
||||
{
|
||||
const qJobComplete = lastProcessResponse as QJobComplete;
|
||||
const newValues = qJobComplete.values;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if the process step sent a new frontend-step-list, then refresh what we have in state (constructing new full model objects) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
let frontendSteps = steps;
|
||||
const updatedFrontendStepList = qJobComplete.updatedFrontendStepList;
|
||||
if (updatedFrontendStepList)
|
||||
{
|
||||
setSteps(updatedFrontendStepList);
|
||||
frontendSteps = updatedFrontendStepList;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// if the next screen has any PVS fields - look up their labels (display values) //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
const nextStepName = qJobComplete.nextStep;
|
||||
let nextStep: QFrontendStepMetaData | null = null;
|
||||
if (frontendSteps && nextStepName)
|
||||
{
|
||||
for (let i = 0; i < frontendSteps.length; i++)
|
||||
{
|
||||
if (frontendSteps[i].name === nextStepName)
|
||||
{
|
||||
nextStep = frontendSteps[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextStep && nextStep.formFields)
|
||||
{
|
||||
for (let i = 0; i < nextStep.formFields.length; i++)
|
||||
{
|
||||
const field = nextStep.formFields[i];
|
||||
const fieldName = field.name;
|
||||
if (field.possibleValueSourceName && newValues && newValues[fieldName])
|
||||
{
|
||||
const results: QPossibleValue[] = await Client.getInstance().possibleValues(null, processName, fieldName, null, [newValues[fieldName]]);
|
||||
if (results && results.length > 0)
|
||||
{
|
||||
if (!cachedPossibleValueLabels[fieldName])
|
||||
{
|
||||
cachedPossibleValueLabels[fieldName] = {};
|
||||
}
|
||||
cachedPossibleValueLabels[fieldName][newValues[fieldName]] = results[0].label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setJobUUID(null);
|
||||
setNewStep(nextStepName);
|
||||
setProcessValues(newValues);
|
||||
setNewStep(qJobComplete.nextStep);
|
||||
setProcessValues(qJobComplete.values);
|
||||
setQJobRunning(null);
|
||||
|
||||
if (formikSetFieldValueFunction)
|
||||
@ -1177,11 +1094,19 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if the process step sent a new frontend-step-list, then refresh what we have in state (constructing new full model objects) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const updatedFrontendStepList = qJobComplete.updatedFrontendStepList;
|
||||
if (updatedFrontendStepList)
|
||||
{
|
||||
setSteps(updatedFrontendStepList);
|
||||
}
|
||||
|
||||
if (activeStep && activeStep.recordListFields)
|
||||
{
|
||||
setNeedRecords(true);
|
||||
}
|
||||
})();
|
||||
}
|
||||
else if (lastProcessResponse instanceof QJobStarted)
|
||||
{
|
||||
@ -1422,11 +1347,8 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
|
||||
const formData = new FormData();
|
||||
Object.keys(values).forEach((key) =>
|
||||
{
|
||||
if (values[key] !== undefined)
|
||||
{
|
||||
formData.append(key, values[key]);
|
||||
}
|
||||
});
|
||||
|
||||
if (tableVariantLocalStorageKey && localStorage.getItem(tableVariantLocalStorageKey))
|
||||
@ -1649,7 +1571,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
);
|
||||
|
||||
const body = (
|
||||
<Box py={3} mb={20} className="processRun">
|
||||
<Box py={3} mb={20}>
|
||||
<Grid container justifyContent="center" alignItems="center" sx={{height: "100%", mt: 8}}>
|
||||
<Grid item xs={12} lg={10} xl={8}>
|
||||
{form}
|
||||
|
@ -94,7 +94,6 @@ interface Props
|
||||
isModal?: boolean;
|
||||
initialQueryFilter?: QQueryFilter;
|
||||
initialColumns?: QQueryColumns;
|
||||
allowVariables?: boolean;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
@ -126,7 +125,7 @@ const getLoadingScreen = (isModal: boolean) =>
|
||||
**
|
||||
** Yuge component. The best. Lots of very smart people are saying so.
|
||||
*******************************************************************************/
|
||||
const RecordQuery = forwardRef(({table, usage, isModal, allowVariables, initialQueryFilter, initialColumns}: Props, ref) =>
|
||||
const RecordQuery = forwardRef(({table, usage, isModal, initialQueryFilter, initialColumns}: Props, ref) =>
|
||||
{
|
||||
const tableName = table.name;
|
||||
const [searchParams] = useSearchParams();
|
||||
@ -631,7 +630,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, allowVariables, initialQ
|
||||
const type = (e.target as any).type;
|
||||
const validType = (type !== "text" && type !== "textarea" && type !== "input" && type !== "search");
|
||||
|
||||
if (validType && !isModal && !dotMenuOpen && !keyboardHelpOpen && !activeModalProcess)
|
||||
if (validType && !dotMenuOpen && !keyboardHelpOpen && !activeModalProcess)
|
||||
{
|
||||
if (!e.metaKey && !e.ctrlKey && e.key === "n" && table.capabilities.has(Capability.TABLE_INSERT) && table.insertPermission)
|
||||
{
|
||||
@ -669,7 +668,7 @@ const RecordQuery = forwardRef(({table, usage, isModal, allowVariables, initialQ
|
||||
{
|
||||
document.removeEventListener("keydown", down);
|
||||
};
|
||||
}, [isModal, dotMenuOpen, keyboardHelpOpen, metaData, activeModalProcess]);
|
||||
}, [dotMenuOpen, keyboardHelpOpen, metaData, activeModalProcess]);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -2885,7 +2884,6 @@ const RecordQuery = forwardRef(({table, usage, isModal, allowVariables, initialQ
|
||||
gridApiRef={gridApiRef}
|
||||
mode={mode}
|
||||
queryScreenUsage={usage}
|
||||
allowVariables={allowVariables}
|
||||
setMode={doSetMode}
|
||||
savedViewsComponent={savedViewsComponent}
|
||||
columnMenuComponent={buildColumnMenu()}
|
||||
@ -2914,7 +2912,6 @@ const RecordQuery = forwardRef(({table, usage, isModal, allowVariables, initialQ
|
||||
metaData: metaData,
|
||||
queryFilter: queryFilter,
|
||||
updateFilter: doSetQueryFilter,
|
||||
allowVariables: allowVariables
|
||||
}
|
||||
}}
|
||||
localeText={{
|
||||
|
@ -717,7 +717,6 @@ input[type="search"]::-webkit-search-results-decoration
|
||||
background-color: #0062FF !important;
|
||||
}
|
||||
|
||||
/* several styles below here for user-defined alert inside helpContent */
|
||||
.helpContentAlert
|
||||
{
|
||||
padding: 6px 16px;
|
||||
@ -780,10 +779,3 @@ input[type="search"]::-webkit-search-results-decoration
|
||||
{
|
||||
color: #F44335;
|
||||
}
|
||||
|
||||
/* the alert widget, was built with minimal (no?) margins, for embedding in
|
||||
a parent widget; but for using it on a process, give it some breathing room */
|
||||
.processRun .widget .MuiAlert-root
|
||||
{
|
||||
margin: 2rem 1rem;
|
||||
}
|
||||
|
Reference in New Issue
Block a user