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 |
@ -97,7 +97,7 @@ export const getAutocompleteOutlinedStyle = (isDisabled: boolean) =>
|
||||
borderColor: inputBorderColor
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const qController = Client.getInstance();
|
||||
@ -108,36 +108,36 @@ 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)
|
||||
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)
|
||||
if(tableName && !fieldName)
|
||||
{
|
||||
console.log("DynamicSelect - if you provide a tableName, you must also provide a fieldName");
|
||||
}
|
||||
if (processName && !fieldName)
|
||||
if(processName && !fieldName)
|
||||
{
|
||||
console.log("DynamicSelect - if you provide a processName, you must also provide a fieldName");
|
||||
}
|
||||
if (!fieldName && !possibleValueSourceName)
|
||||
if(!fieldName && !possibleValueSourceName)
|
||||
{
|
||||
console.log("DynamicSelect - you must provide either a fieldName (and a tableName or processName) or a possibleValueSourceName");
|
||||
}
|
||||
if (fieldName && !possibleValueSourceName)
|
||||
if(fieldName && !possibleValueSourceName)
|
||||
{
|
||||
if (!tableName || !processName)
|
||||
if(!tableName || !processName)
|
||||
{
|
||||
console.log("DynamicSelect - if you provide a fieldName and not a possibleValueSourceName, then you must also provide a tableName or processName");
|
||||
}
|
||||
}
|
||||
if (possibleValueSourceName)
|
||||
if(possibleValueSourceName)
|
||||
{
|
||||
if (tableName || processName)
|
||||
if(tableName || processName)
|
||||
{
|
||||
console.log("DynamicSelect - if you provide a possibleValueSourceName, you should not also provide a tableName or processName");
|
||||
}
|
||||
@ -173,7 +173,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if (firstRender)
|
||||
if(firstRender)
|
||||
{
|
||||
// console.log("First render, so not searching...");
|
||||
setFirstRender(false);
|
||||
@ -196,7 +196,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
// console.log(`doing a search with ${searchTerm}`);
|
||||
const results: QPossibleValue[] = await qController.possibleValues(tableName, processName, possibleValueSourceName ?? fieldName, searchTerm ?? "", null, otherValues);
|
||||
|
||||
if (tableMetaData == null && tableName)
|
||||
if(tableMetaData == null && tableName)
|
||||
{
|
||||
let tableMetaData: QTableMetaData = await qController.loadTableMetaData(tableName);
|
||||
setTableMetaData(tableMetaData);
|
||||
@ -207,7 +207,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
// console.log(`${results}`);
|
||||
if (active)
|
||||
{
|
||||
setOptions([...results]);
|
||||
setOptions([ ...results ]);
|
||||
}
|
||||
})();
|
||||
|
||||
@ -215,12 +215,12 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
{
|
||||
active = false;
|
||||
};
|
||||
}, [searchTerm]);
|
||||
}, [ searchTerm ]);
|
||||
|
||||
// todo - finish... call it in onOpen?
|
||||
const reloadIfOtherValuesAreChanged = () =>
|
||||
{
|
||||
if (JSON.stringify(Object.fromEntries(otherValues)) != otherValuesWhenResultsWereLoaded)
|
||||
if(JSON.stringify(Object.fromEntries(otherValues)) != otherValuesWhenResultsWereLoaded)
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
@ -229,16 +229,16 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
console.log("Refreshing possible values...");
|
||||
const results: QPossibleValue[] = await qController.possibleValues(tableName, processName, possibleValueSourceName ?? fieldName, searchTerm ?? "", null, otherValues);
|
||||
setLoading(false);
|
||||
setOptions([...results]);
|
||||
setOptions([ ...results ]);
|
||||
setOtherValuesWhenResultsWereLoaded(JSON.stringify(Object.fromEntries(otherValues)));
|
||||
})();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const inputChanged = (event: React.SyntheticEvent, value: string, reason: string) =>
|
||||
{
|
||||
// console.log(`input changed. Reason: ${reason}, setting search term to ${value}`);
|
||||
if (reason !== "reset")
|
||||
if(reason !== "reset")
|
||||
{
|
||||
// console.log(` -> setting search term to ${value}`);
|
||||
setSearchTerm(value);
|
||||
@ -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) =>
|
||||
{
|
||||
@ -256,9 +256,9 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
// console.log(value);
|
||||
setSearchTerm(null);
|
||||
|
||||
if (onChange)
|
||||
if(onChange)
|
||||
{
|
||||
if (isMultiple)
|
||||
if(isMultiple)
|
||||
{
|
||||
onChange(value);
|
||||
}
|
||||
@ -267,7 +267,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
onChange(value ? new QPossibleValue(value) : null);
|
||||
}
|
||||
}
|
||||
else if (setFieldValueRef && fieldName)
|
||||
else if(setFieldValueRef && fieldName)
|
||||
{
|
||||
setFieldValueRef(fieldName, value ? value.id : null);
|
||||
}
|
||||
@ -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,24 +289,23 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
|
||||
try
|
||||
{
|
||||
const field = tableMetaData?.fields.get(fieldName);
|
||||
if (field)
|
||||
const field = tableMetaData?.fields.get(fieldName)
|
||||
if(field)
|
||||
{
|
||||
const adornment = field.getAdornment(AdornmentType.CHIP);
|
||||
if (adornment)
|
||||
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}} />);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
catch(e)
|
||||
{ }
|
||||
|
||||
if (isMultiple)
|
||||
if(isMultiple)
|
||||
{
|
||||
content = (
|
||||
<>
|
||||
@ -328,7 +327,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
{content}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
const bulkEditSwitchChanged = () =>
|
||||
{
|
||||
@ -358,7 +357,7 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
{
|
||||
setOpen(true);
|
||||
// console.log("setting open...");
|
||||
if (options.length == 0)
|
||||
if(options.length == 0)
|
||||
{
|
||||
// console.log("no options yet, so setting search term to ''...");
|
||||
setSearchTerm("");
|
||||
@ -371,19 +370,19 @@ function DynamicSelect({tableName, processName, fieldName, possibleValueSourceNa
|
||||
isOptionEqualToValue={(option, value) => value !== null && value !== undefined && option.id === value.id}
|
||||
getOptionLabel={(option) =>
|
||||
{
|
||||
if (option === null || option === undefined)
|
||||
if(option === null || option === undefined)
|
||||
{
|
||||
return ("");
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (option && option.length)
|
||||
if(option && option.length)
|
||||
{
|
||||
// @ts-ignore
|
||||
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}
|
||||
/>;
|
||||
|
@ -63,7 +63,7 @@ function QBreadcrumbs({icon, title, route, light}: Props): JSX.Element
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// strip away empty elements of the route (e.g., trailing slash(es)) //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
if (route.length)
|
||||
if(route.length)
|
||||
{
|
||||
// @ts-ignore
|
||||
route = route.filter(r => r != "");
|
||||
@ -74,18 +74,18 @@ function QBreadcrumbs({icon, title, route, light}: Props): JSX.Element
|
||||
|
||||
const fullPathToLabel = (fullPath: string, route: string): string =>
|
||||
{
|
||||
if (fullPath.endsWith("/"))
|
||||
if(fullPath.endsWith("/"))
|
||||
{
|
||||
fullPath = fullPath.replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
if (pathToLabelMap && pathToLabelMap[fullPath])
|
||||
if(pathToLabelMap && pathToLabelMap[fullPath])
|
||||
{
|
||||
return pathToLabelMap[fullPath];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -106,12 +106,12 @@ function QBreadcrumbs({icon, title, route, light}: Props): JSX.Element
|
||||
// e.g., when at /app/table/savedView/1 (so where i==1) //
|
||||
// we want to just be showing "App" //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
if (i < routes.length - 1 && routes[i + 1] == "savedView" && i == 1)
|
||||
if(i < routes.length - 1 && routes[i+1] == "savedView" && i == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (routes[i] === "")
|
||||
if(routes[i] === "")
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -133,12 +133,12 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
|
||||
const handleAutocompleteOnChange = (event: any, value: any, reason: any, details: any) =>
|
||||
{
|
||||
if (value)
|
||||
if(value)
|
||||
{
|
||||
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 = () =>
|
||||
{
|
||||
@ -166,7 +166,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
PopperComponent={CustomPopper}
|
||||
isOptionEqualToValue={(option, value) => option.id === value.id}
|
||||
sx={recentlyViewedMenu}
|
||||
renderInput={(params) => <TextField {...params} label="Recently Viewed Records" InputProps={{
|
||||
renderInput={(params) => <TextField {...params} label="Recently Viewed Records" InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
@ -184,7 +184,7 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
// Styles for the navbar icons
|
||||
const iconsStyle = ({
|
||||
@ -210,18 +210,18 @@ function NavBar({absolute, light, isMini}: Props): JSX.Element
|
||||
const {pathToLabelMap} = useContext(QContext);
|
||||
const fullPathToLabel = (fullPath: string, route: string): string =>
|
||||
{
|
||||
if (fullPath.endsWith("/"))
|
||||
if(fullPath.endsWith("/"))
|
||||
{
|
||||
fullPath = fullPath.replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
if (pathToLabelMap && pathToLabelMap[fullPath])
|
||||
if(pathToLabelMap && pathToLabelMap[fullPath])
|
||||
{
|
||||
return pathToLabelMap[fullPath];
|
||||
}
|
||||
|
||||
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">
|
||||
|
@ -39,7 +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 React, {SyntheticEvent, useReducer, useState} from "react";
|
||||
|
||||
interface Props
|
||||
{
|
||||
@ -50,7 +50,6 @@ interface Props
|
||||
valueChangeHandler: (event: React.ChangeEvent | SyntheticEvent, valueIndex?: number | "all", newValue?: any) => void;
|
||||
initiallyOpenMultiValuePvs?: boolean;
|
||||
queryScreenUsage?: QueryScreenUsage;
|
||||
allowVariables?: boolean;
|
||||
}
|
||||
|
||||
FilterCriteriaRowValues.defaultProps =
|
||||
@ -188,9 +187,10 @@ export const makeTextField = (field: QFieldMetaData, criteria: QFilterCriteriaWi
|
||||
};
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
@ -320,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,20 +443,7 @@ 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.initialDisplayValue = processValues[key];
|
||||
}
|
||||
|
||||
formFields[key].possibleValueProps.otherValues = formFields[key].possibleValueProps.otherValues ?? new Map<string, any>();
|
||||
@ -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]);
|
||||
}
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1100,88 +1073,40 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
|
||||
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;
|
||||
setJobUUID(null);
|
||||
setNewStep(qJobComplete.nextStep);
|
||||
setProcessValues(qJobComplete.values);
|
||||
setQJobRunning(null);
|
||||
|
||||
if (formikSetFieldValueFunction)
|
||||
{
|
||||
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)
|
||||
//////////////////////////////////
|
||||
// reset field values in formik //
|
||||
//////////////////////////////////
|
||||
for (let key in qJobComplete.values)
|
||||
{
|
||||
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 (Object.hasOwn(formFields, key))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(`(re)setting form field [${key}] to [${qJobComplete.values[key]}]`);
|
||||
formikSetFieldValueFunction(key, qJobComplete.values[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setJobUUID(null);
|
||||
setNewStep(nextStepName);
|
||||
setProcessValues(newValues);
|
||||
setQJobRunning(null);
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 (formikSetFieldValueFunction)
|
||||
{
|
||||
//////////////////////////////////
|
||||
// reset field values in formik //
|
||||
//////////////////////////////////
|
||||
for (let key in qJobComplete.values)
|
||||
{
|
||||
if (Object.hasOwn(formFields, key))
|
||||
{
|
||||
console.log(`(re)setting form field [${key}] to [${qJobComplete.values[key]}]`);
|
||||
formikSetFieldValueFunction(key, qJobComplete.values[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activeStep && activeStep.recordListFields)
|
||||
{
|
||||
setNeedRecords(true);
|
||||
}
|
||||
})();
|
||||
if (activeStep && activeStep.recordListFields)
|
||||
{
|
||||
setNeedRecords(true);
|
||||
}
|
||||
}
|
||||
else if (lastProcessResponse instanceof QJobStarted)
|
||||
{
|
||||
@ -1646,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