Fixes for column stats with joins; fix some js console warnings;

This commit is contained in:
2023-05-04 10:54:15 -05:00
parent 061ddc7f4a
commit cbaeb3cce4
4 changed files with 116 additions and 66 deletions

View File

@ -294,13 +294,8 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// we don't want this job to go async, so, pass a large timeout // // we don't want this job to go async, so, pass a large timeout //
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
formData.append("_qStepTimeoutMillis", 60 * 1000); formData.append(QController.STEP_TIMEOUT_MILLIS_PARAM_NAME, 60 * 1000);
const processResult = await qController.processInit(processName, formData, qController.defaultMultipartFormDataHeaders());
const formDataHeaders = {
"content-type": "multipart/form-data; boundary=--------------------------320289315924586491558366",
};
const processResult = await qController.processInit(processName, formData, formDataHeaders);
if (processResult instanceof QJobError) if (processResult instanceof QJobError)
{ {
const jobError = processResult as QJobError; const jobError = processResult as QJobError;
@ -346,7 +341,7 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
onClose={closeSavedFiltersMenu} onClose={closeSavedFiltersMenu}
keepMounted keepMounted
> >
<MenuItem sx={{width: "300px"}}><b>Filter Actions</b></MenuItem> <MenuItem sx={{width: "300px"}} disabled style={{"opacity": "initial"}}><b>Filter Actions</b></MenuItem>
{ {
hasStorePermission && hasStorePermission &&
<MenuItem onClick={() => handleDropdownOptionClick(SAVE_OPTION)}> <MenuItem onClick={() => handleDropdownOptionClick(SAVE_OPTION)}>
@ -382,7 +377,7 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
</MenuItem> </MenuItem>
} }
<Divider/> <Divider/>
<MenuItem><b>Your Filters</b></MenuItem> <MenuItem disabled style={{"opacity": "initial"}}><b>Your Filters</b></MenuItem>
{ {
savedFilters && savedFilters.length > 0 ? ( savedFilters && savedFilters.length > 0 ? (
savedFilters.map((record: QRecord, index: number) => savedFilters.map((record: QRecord, index: number) =>
@ -413,7 +408,7 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
{currentSavedFilter.values.get("label")} {currentSavedFilter.values.get("label")}
{ {
filterIsModified && ( filterIsModified && (
<Tooltip sx={{cursor: "pointer"}} title={"The current filter has been modified, click \"Save...\" to save the changes."}> <Tooltip sx={{cursor: "pointer"}} title={"The current filter has been modified. Click \"Save...\" to save the changes."}>
<FiberManualRecord sx={{color: "orange", paddingLeft: "2px", paddingTop: "4px"}} /> <FiberManualRecord sx={{color: "orange", paddingLeft: "2px", paddingTop: "4px"}} />
</Tooltip> </Tooltip>
) )
@ -430,6 +425,13 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
onClose={handleSaveFilterPopupClose} onClose={handleSaveFilterPopupClose}
aria-labelledby="alert-dialog-title" aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description" aria-describedby="alert-dialog-description"
onKeyPress={(e) =>
{
if (e.key == "Enter")
{
handleFilterDialogButtonOnClick();
}
}}
> >
{ {
currentSavedFilter ? ( currentSavedFilter ? (
@ -479,7 +481,6 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
):( ):(
isDeleteFilter ? ( isDeleteFilter ? (
<Box>Are you sure you want to delete the filter {`'${currentSavedFilter?.values.get("label")}'`}?</Box> <Box>Are you sure you want to delete the filter {`'${currentSavedFilter?.values.get("label")}'`}?</Box>
):( ):(
<Box>Are you sure you want to update the filter {`'${currentSavedFilter?.values.get("label")}'`} with the current filter criteria?</Box> <Box>Are you sure you want to update the filter {`'${currentSavedFilter?.values.get("label")}'`} with the current filter criteria?</Box>
) )

View File

@ -44,6 +44,7 @@ interface Props
{ {
tableMetaData: QTableMetaData; tableMetaData: QTableMetaData;
fieldMetaData: QFieldMetaData; fieldMetaData: QFieldMetaData;
fieldTableName: string;
filter: QQueryFilter; filter: QQueryFilter;
} }
@ -52,7 +53,7 @@ ColumnStats.defaultProps = {
const qController = Client.getInstance(); const qController = Client.getInstance();
function ColumnStats({tableMetaData, fieldMetaData, filter}: Props): JSX.Element function ColumnStats({tableMetaData, fieldMetaData, fieldTableName, filter}: Props): JSX.Element
{ {
const [statusString, setStatusString] = useState("Calculating statistics..."); const [statusString, setStatusString] = useState("Calculating statistics...");
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@ -73,9 +74,11 @@ function ColumnStats({tableMetaData, fieldMetaData, filter}: Props): JSX.Element
(async () => (async () =>
{ {
const fullFieldName = (fieldTableName == tableMetaData.name ? "" : `${fieldTableName}.`) + fieldMetaData.name;
const formData = new FormData(); const formData = new FormData();
formData.append("tableName", tableMetaData.name); formData.append("tableName", tableMetaData.name);
formData.append("fieldName", fieldMetaData.name); formData.append("fieldName", fullFieldName);
formData.append("filterJSON", JSON.stringify(filter)); formData.append("filterJSON", JSON.stringify(filter));
if(orderBy) if(orderBy)
{ {
@ -115,7 +118,16 @@ function ColumnStats({tableMetaData, fieldMetaData, filter}: Props): JSX.Element
const valueCounts = [] as QRecord[]; const valueCounts = [] as QRecord[];
for(let i = 0; i < result.values.valueCounts.length; i++) for(let i = 0; i < result.values.valueCounts.length; i++)
{ {
valueCounts.push(new QRecord(result.values.valueCounts[i])); let valueRecord = new QRecord(result.values.valueCounts[i]);
////////////////////////////////////////////////////////////////////////////////////////////////
// for a field from a join, the backend will have sent it as table.field (e.g., lineItem.sku) //
// but we'll have a "better time" in the rest of this code if we have it as just the field //
// name, so, copy it there... //
////////////////////////////////////////////////////////////////////////////////////////////////
valueRecord.displayValues.set(fieldMetaData.name, valueRecord.displayValues.get(fullFieldName));
valueRecord.values.set(fieldMetaData.name, valueRecord.values.get(fullFieldName));
valueCounts.push(valueRecord);
} }
setValueCounts(valueCounts); setValueCounts(valueCounts);
@ -128,6 +140,7 @@ function ColumnStats({tableMetaData, fieldMetaData, filter}: Props): JSX.Element
const rows = DataGridUtils.makeRows(valueCounts, fakeTableMetaData); const rows = DataGridUtils.makeRows(valueCounts, fakeTableMetaData);
const columns = DataGridUtils.setupGridColumns(fakeTableMetaData, null, null, "bySection"); const columns = DataGridUtils.setupGridColumns(fakeTableMetaData, null, null, "bySection");
columns.forEach((c) => columns.forEach((c) =>
{ {
c.width = 200; c.width = 200;

View File

@ -19,14 +19,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {QController} from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
import {Capability} from "@kingsrook/qqq-frontend-core/lib/model/metaData/Capability"; import {Capability} from "@kingsrook/qqq-frontend-core/lib/model/metaData/Capability";
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance"; import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData"; import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete"; import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete";
import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError"; import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord"; import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter"; import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
import {QueryJoin} from "@kingsrook/qqq-frontend-core/lib/model/query/QueryJoin"; import {QueryJoin} from "@kingsrook/qqq-frontend-core/lib/model/query/QueryJoin";
import {Alert, Box, Collapse, TablePagination} from "@mui/material"; import {Alert, Box, Collapse, TablePagination} from "@mui/material";
@ -194,6 +195,8 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
const [launchingProcess, setLaunchingProcess] = useState(launchProcess); const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
const [recordIdsForProcess, setRecordIdsForProcess] = useState(null as string | QQueryFilter); const [recordIdsForProcess, setRecordIdsForProcess] = useState(null as string | QQueryFilter);
const [columnStatsFieldName, setColumnStatsFieldName] = useState(null as string); const [columnStatsFieldName, setColumnStatsFieldName] = useState(null as string);
const [columnStatsField, setColumnStatsField] = useState(null as QFieldMetaData);
const [columnStatsFieldTableName, setColumnStatsFieldTableName] = useState(null as string)
const [filterForColumnStats, setFilterForColumnStats] = useState(null as QQueryFilter); const [filterForColumnStats, setFilterForColumnStats] = useState(null as QQueryFilter);
const instance = useRef({timer: null}); const instance = useRef({timer: null});
@ -280,17 +283,8 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
{ {
const formData = new FormData(); const formData = new FormData();
formData.append("id", currentSavedFilterId); formData.append("id", currentSavedFilterId);
formData.append(QController.STEP_TIMEOUT_MILLIS_PARAM_NAME, 60 * 1000);
////////////////////////////////////////////////////////////////// const processResult = await qController.processInit("querySavedFilter", formData, qController.defaultMultipartFormDataHeaders());
// we don't want this job to go async, so, pass a large timeout //
//////////////////////////////////////////////////////////////////
formData.append("_qStepTimeoutMillis", 60 * 1000);
const formDataHeaders = {
"content-type": "multipart/form-data; boundary=--------------------------320289315924586491558366",
};
const processResult = await qController.processInit("querySavedFilter", formData, formDataHeaders);
if (processResult instanceof QJobError) if (processResult instanceof QJobError)
{ {
const jobError = processResult as QJobError; const jobError = processResult as QJobError;
@ -1065,6 +1059,8 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
} }
setColumnStatsFieldName(null); setColumnStatsFieldName(null);
setColumnStatsFieldTableName(null);
setColumnStatsField(null);
}; };
const closeModalProcess = (event: object, reason: string) => const closeModalProcess = (event: object, reason: string) =>
@ -1140,8 +1136,8 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
that match your query, because you have included fields from other tables which may have that match your query, because you have included fields from other tables which may have
more than one record associated with each {tableMetaData?.label}. more than one record associated with each {tableMetaData?.label}.
</> </>
let distinctPart = isJoinMany(tableMetaData, getVisibleJoinTables()) ? (<Box display="inline" textAlign="right"> let distinctPart = isJoinMany(tableMetaData, getVisibleJoinTables()) ? (<Box display="inline" component="span" textAlign="right">
&nbsp;({distinctRecords} distinct<CustomWidthTooltip title={tooltipHTML}> &nbsp;({safeToLocaleString(distinctRecords)} distinct<CustomWidthTooltip title={tooltipHTML}>
<IconButton sx={{p: 0, pl: 0.25, mb: 0.25}}><Icon fontSize="small" sx={{fontSize: "1.125rem !important", color: "#9f9f9f"}}>info_outlined</Icon></IconButton> <IconButton sx={{p: 0, pl: 0.25, mb: 0.25}}><Icon fontSize="small" sx={{fontSize: "1.125rem !important", color: "#9f9f9f"}}>info_outlined</Icon></IconButton>
</CustomWidthTooltip> </CustomWidthTooltip>
) )
@ -1170,14 +1166,14 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
return (loading ? "Counting..." : "No rows"); return (loading ? "Counting..." : "No rows");
} }
return <> return <span>
Showing {from.toLocaleString()} to {to.toLocaleString()} of Showing {from.toLocaleString()} to {to.toLocaleString()} of
{ {
count == -1 ? count == -1 ?
<>more than {to.toLocaleString()}</> <>more than {to.toLocaleString()}</>
: <> {count.toLocaleString()}{distinctPart}</> : <> {count.toLocaleString()}{distinctPart}</>
} }
</>; </span>;
} }
else else
{ {
@ -1215,6 +1211,8 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
if (selectedSavedFilterId != null) if (selectedSavedFilterId != null)
{ {
const qRecord = await fetchSavedFilter(selectedSavedFilterId); const qRecord = await fetchSavedFilter(selectedSavedFilterId);
setCurrentSavedFilter(qRecord); // this fixed initial load not showing filter name
const models = await FilterUtils.determineFilterAndSortModels(qController, tableMetaData, qRecord.values.get("filterJson"), null, null, null); const models = await FilterUtils.determineFilterAndSortModels(qController, tableMetaData, qRecord.values.get("filterJson"), null, null, null);
handleFilterChange(models.filter); handleFilterChange(models.filter);
handleSortChange(models.sort); handleSortChange(models.sort);
@ -1233,17 +1231,8 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
let qRecord = null; let qRecord = null;
const formData = new FormData(); const formData = new FormData();
formData.append("id", filterId); formData.append("id", filterId);
formData.append(QController.STEP_TIMEOUT_MILLIS_PARAM_NAME, 60 * 1000);
////////////////////////////////////////////////////////////////// const processResult = await qController.processInit("querySavedFilter", formData, qController.defaultMultipartFormDataHeaders());
// we don't want this job to go async, so, pass a large timeout //
//////////////////////////////////////////////////////////////////
formData.append("_qStepTimeoutMillis", 60 * 1000);
const formDataHeaders = {
"content-type": "multipart/form-data; boundary=--------------------------320289315924586491558366",
};
const processResult = await qController.processInit("querySavedFilter", formData, formDataHeaders);
if (processResult instanceof QJobError) if (processResult instanceof QJobError)
{ {
const jobError = processResult as QJobError; const jobError = processResult as QJobError;
@ -1293,6 +1282,25 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
{ {
setFilterForColumnStats(buildQFilter(tableMetaData, filterModel)); setFilterForColumnStats(buildQFilter(tableMetaData, filterModel));
setColumnStatsFieldName(column.field); setColumnStatsFieldName(column.field);
if(column.field.indexOf(".") > -1)
{
const nameParts = column.field.split(".", 2);
for (let i = 0; i < tableMetaData?.exposedJoins?.length; i++)
{
const join = tableMetaData?.exposedJoins[i];
if(join?.joinTable.name == nameParts[0])
{
setColumnStatsField(join.joinTable.fields.get(nameParts[1]));
setColumnStatsFieldTableName(nameParts[0]);
}
}
}
else
{
setColumnStatsField(tableMetaData.fields.get(column.field));
setColumnStatsFieldTableName(tableMetaData.name);
}
}; };
const CustomColumnMenu = forwardRef<HTMLUListElement, GridColumnMenuProps>( const CustomColumnMenu = forwardRef<HTMLUListElement, GridColumnMenuProps>(
@ -1439,6 +1447,15 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
} }
); );
const safeToLocaleString = (n: Number): string =>
{
if(n != null && n != undefined)
{
return (n.toLocaleString());
}
return ("");
}
function CustomToolbar() function CustomToolbar()
{ {
const handleMouseDown: GridEventListener<"cellMouseDown"> = ( const handleMouseDown: GridEventListener<"cellMouseDown"> = (
@ -1473,15 +1490,6 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
const joinIsMany = isJoinMany(tableMetaData, visibleJoinTables); const joinIsMany = isJoinMany(tableMetaData, visibleJoinTables);
const safeToLocaleString = (n: Number): string =>
{
if(n != null && n != undefined)
{
return (n.toLocaleString());
}
return ("");
}
const selectionMenuOptions: string[] = []; const selectionMenuOptions: string[] = [];
selectionMenuOptions.push(`This page (${safeToLocaleString(distinctRecordsOnPageCount)} ${joinIsMany ? "distinct " : ""}record${distinctRecordsOnPageCount == 1 ? "" : "s"})`); selectionMenuOptions.push(`This page (${safeToLocaleString(distinctRecordsOnPageCount)} ${joinIsMany ? "distinct " : ""}record${distinctRecordsOnPageCount == 1 ? "" : "s"})`);
selectionMenuOptions.push(`Full query result (${joinIsMany ? safeToLocaleString(distinctRecords) + ` distinct record${distinctRecords == 1 ? "" : "s"}` : safeToLocaleString(totalRecords) + ` record${totalRecords == 1 ? "" : "s"}`})`); selectionMenuOptions.push(`Full query result (${joinIsMany ? safeToLocaleString(distinctRecords) + ` distinct record${distinctRecords == 1 ? "" : "s"}` : safeToLocaleString(totalRecords) + ` record${totalRecords == 1 ? "" : "s"}`})`);
@ -1552,9 +1560,11 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
Refresh Refresh
</Button> </Button>
</div> </div>
<GridToolbarColumnsButton nonce={undefined} onResize={undefined} onResizeCapture={undefined} /> {/* @ts-ignore */}
<GridToolbarColumnsButton nonce={undefined} />
<div style={{position: "relative"}}> <div style={{position: "relative"}}>
<GridToolbarFilterButton nonce={undefined} onResize={undefined} onResizeCapture={undefined} /> {/* @ts-ignore */}
<GridToolbarFilterButton nonce={undefined} />
{ {
hasValidFilters && ( hasValidFilters && (
@ -1567,7 +1577,6 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
if (e.key == "Enter") if (e.key == "Enter")
{ {
setShowClearFiltersWarning(false) setShowClearFiltersWarning(false)
navigate(metaData.getTablePathByName(tableName));
handleFilterChange({items: []} as GridFilterModel); handleFilterChange({items: []} as GridFilterModel);
} }
}}> }}>
@ -1580,7 +1589,6 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
<QSaveButton label="Yes" iconName="check" disabled={false} onClickHandler={() => <QSaveButton label="Yes" iconName="check" disabled={false} onClickHandler={() =>
{ {
setShowClearFiltersWarning(false); setShowClearFiltersWarning(false);
navigate(metaData.getTablePathByName(tableName));
handleFilterChange({items: []} as GridFilterModel); handleFilterChange({items: []} as GridFilterModel);
}}/> }}/>
</DialogActions> </DialogActions>
@ -1588,8 +1596,10 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
</div> </div>
) )
} }
<GridToolbarDensitySelector nonce={undefined} onResize={undefined} onResizeCapture={undefined} /> {/* @ts-ignore */}
<GridToolbarExportContainer nonce={undefined} onResize={undefined} onResizeCapture={undefined}> <GridToolbarDensitySelector nonce={undefined} />
{/* @ts-ignore */}
<GridToolbarExportContainer nonce={undefined}>
<ExportMenuItem format="csv" /> <ExportMenuItem format="csv" />
<ExportMenuItem format="xlsx" /> <ExportMenuItem format="xlsx" />
<ExportMenuItem format="json" /> <ExportMenuItem format="json" />
@ -1671,22 +1681,22 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
{ {
if (menuItems.length > 0) if (menuItems.length > 0)
{ {
menuItems.push(<Divider />); menuItems.push(<Divider key="divider" />);
} }
}; };
const menuItems: JSX.Element[] = []; const menuItems: JSX.Element[] = [];
if (table.capabilities.has(Capability.TABLE_INSERT) && table.insertPermission) if (table.capabilities.has(Capability.TABLE_INSERT) && table.insertPermission)
{ {
menuItems.push(<MenuItem onClick={bulkLoadClicked}><ListItemIcon><Icon>library_add</Icon></ListItemIcon>Bulk Load</MenuItem>); menuItems.push(<MenuItem key="bulkLoad" onClick={bulkLoadClicked}><ListItemIcon><Icon>library_add</Icon></ListItemIcon>Bulk Load</MenuItem>);
} }
if (table.capabilities.has(Capability.TABLE_UPDATE) && table.editPermission) if (table.capabilities.has(Capability.TABLE_UPDATE) && table.editPermission)
{ {
menuItems.push(<MenuItem onClick={bulkEditClicked}><ListItemIcon><Icon>edit</Icon></ListItemIcon>Bulk Edit</MenuItem>); menuItems.push(<MenuItem key="bulkEdit" onClick={bulkEditClicked}><ListItemIcon><Icon>edit</Icon></ListItemIcon>Bulk Edit</MenuItem>);
} }
if (table.capabilities.has(Capability.TABLE_DELETE) && table.deletePermission) if (table.capabilities.has(Capability.TABLE_DELETE) && table.deletePermission)
{ {
menuItems.push(<MenuItem onClick={bulkDeleteClicked}><ListItemIcon><Icon>delete</Icon></ListItemIcon>Bulk Delete</MenuItem>); menuItems.push(<MenuItem key="bulkDelete" onClick={bulkDeleteClicked}><ListItemIcon><Icon>delete</Icon></ListItemIcon>Bulk Delete</MenuItem>);
} }
const runRecordScriptProcess = metaData?.processes.get("runRecordScript"); const runRecordScriptProcess = metaData?.processes.get("runRecordScript");
@ -1696,7 +1706,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
menuItems.push(<MenuItem key={process.name} onClick={() => processClicked(process)}><ListItemIcon><Icon>{process.iconName ?? "arrow_forward"}</Icon></ListItemIcon>{process.label}</MenuItem>); menuItems.push(<MenuItem key={process.name} onClick={() => processClicked(process)}><ListItemIcon><Icon>{process.iconName ?? "arrow_forward"}</Icon></ListItemIcon>{process.label}</MenuItem>);
} }
menuItems.push(<MenuItem onClick={() => navigate("dev")}><ListItemIcon><Icon>code</Icon></ListItemIcon>Developer Mode</MenuItem>); menuItems.push(<MenuItem key="developerMode" onClick={() => navigate("dev")}><ListItemIcon><Icon>code</Icon></ListItemIcon>Developer Mode</MenuItem>);
if (tableProcesses && tableProcesses.length) if (tableProcesses && tableProcesses.length)
{ {
@ -1711,7 +1721,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
if (menuItems.length === 0) if (menuItems.length === 0)
{ {
menuItems.push(<MenuItem disabled><ListItemIcon><Icon>block</Icon></ListItemIcon><i>No actions available</i></MenuItem>); menuItems.push(<MenuItem key="notAvaialableNow" disabled><ListItemIcon><Icon>block</Icon></ListItemIcon><i>No actions available</i></MenuItem>);
} }
const renderActionsMenu = ( const renderActionsMenu = (
@ -1898,7 +1908,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
<Box sx={{position: "absolute", overflowY: "auto", maxHeight: "100%", width: "100%"}}> <Box sx={{position: "absolute", overflowY: "auto", maxHeight: "100%", width: "100%"}}>
<Card sx={{my: 5, mx: "auto", pb: 0, maxWidth: "1024px"}}> <Card sx={{my: 5, mx: "auto", pb: 0, maxWidth: "1024px"}}>
<Box component="div"> <Box component="div">
<ColumnStats tableMetaData={tableMetaData} fieldMetaData={tableMetaData?.fields.get(columnStatsFieldName)} filter={filterForColumnStats} /> <ColumnStats tableMetaData={tableMetaData} fieldMetaData={columnStatsField} fieldTableName={columnStatsFieldTableName} filter={filterForColumnStats} />
<Box p={3} display="flex" flexDirection="row" justifyContent="flex-end"> <Box p={3} display="flex" flexDirection="row" justifyContent="flex-end">
<QCancelButton label="Close" onClickHandler={() => closeColumnStats(null, null)} disabled={false} /> <QCancelButton label="Close" onClickHandler={() => closeColumnStats(null, null)} disabled={false} />
</Box> </Box>

View File

@ -360,7 +360,7 @@ class FilterUtils
let defaultFilter = {items: []} as GridFilterModel; let defaultFilter = {items: []} as GridFilterModel;
let defaultSort = [] as GridSortItem[]; let defaultSort = [] as GridSortItem[];
if (tableMetaData.fields !== undefined) if (tableMetaData && tableMetaData.fields !== undefined)
{ {
if (filterString != null || (searchParams && searchParams.has("filter"))) if (filterString != null || (searchParams && searchParams.has("filter")))
{ {
@ -376,7 +376,33 @@ class FilterUtils
for (let i = 0; i < qQueryFilter?.criteria?.length; i++) for (let i = 0; i < qQueryFilter?.criteria?.length; i++)
{ {
const criteria = qQueryFilter.criteria[i]; const criteria = qQueryFilter.criteria[i];
const field = tableMetaData.fields.get(criteria.fieldName); let fieldTable = tableMetaData;
let field = null;
if (criteria.fieldName.indexOf(".") > -1)
{
const nameParts = criteria.fieldName.split(".", 2);
for (let i = 0; i < tableMetaData?.exposedJoins?.length; i++)
{
const joinTable = tableMetaData.exposedJoins[i].joinTable;
if (joinTable.name == nameParts[0])
{
fieldTable = joinTable;
field = joinTable.fields.get(nameParts[1]);
break;
}
}
}
else
{
field = tableMetaData.fields.get(criteria.fieldName);
}
if (field == null)
{
console.log("Couldn't find field for filter: " + criteria.fieldName);
continue;
}
let values = criteria.values; let values = criteria.values;
if (field.possibleValueSourceName) if (field.possibleValueSourceName)
{ {
@ -388,7 +414,7 @@ class FilterUtils
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
if (values && values.length > 0) if (values && values.length > 0)
{ {
values = await qController.possibleValues(tableMetaData.name, null, field.name, "", values); values = await qController.possibleValues(fieldTable.name, null, field.name, "", values);
} }
//////////////////////////////////////////// ////////////////////////////////////////////