diff --git a/src/qqq/pages/entity-list/index.tsx b/src/qqq/pages/entity-list/index.tsx
index 4d3f971..548b725 100644
--- a/src/qqq/pages/entity-list/index.tsx
+++ b/src/qqq/pages/entity-list/index.tsx
@@ -22,6 +22,7 @@
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
+import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy";
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
@@ -162,6 +163,15 @@ function EntityList({table}: Props): JSX.Element
const [pinnedColumns, setPinnedColumns] = useState({left: ["__check__", "id"]});
const instance = useRef({timer: null});
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // use all these states to avoid showing results from an "old" query, that finishes loading after a newer one //
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ const [latestQueryId, setLatestQueryId] = useState(0);
+ const [countResults, setCountResults] = useState({} as any);
+ const [receivedCountTimestamp, setReceivedCountTimestamp] = useState(new Date());
+ const [queryResults, setQueryResults] = useState({} as any);
+ const [receivedQueryTimestamp, setReceivedQueryTimestamp] = useState(new Date());
+
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
@@ -200,7 +210,6 @@ function EntityList({table}: Props): JSX.Element
////////////////////////////////////////////////////////////////////////////////////////////////
// we need the table meta data to look up the default filter (if it comes from query string), //
// because we need to know field types to translate qqq filter to material filter //
- // because we need to know field types to translate qqq filter to material filter //
// return here ane wait for the next 'turn' to allow doing the actual query //
////////////////////////////////////////////////////////////////////////////////////////////////
if (!defaultFilterLoaded)
@@ -210,6 +219,7 @@ function EntityList({table}: Props): JSX.Element
return;
}
setTableMetaData(tableMetaData);
+ setTableLabel(tableMetaData.label);
if (columnSortModel.length === 0)
{
columnSortModel.push({
@@ -222,121 +232,175 @@ function EntityList({table}: Props): JSX.Element
const qFilter = buildQFilter();
- const count = await qController.count(tableName, qFilter);
- setTotalRecords(count);
- setTableLabel(tableMetaData.label);
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ // assign a new query id to the query being issued here. then run both the count & query async //
+ // and when they load, store their results associated with this id. //
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ const thisQueryId = latestQueryId + 1
+ setLatestQueryId(thisQueryId);
- const columns = [] as GridColDef[];
+ console.log(`Issuing query: ${thisQueryId}`);
+ setTotalRecords(null);
+ qController.count(tableName, qFilter).then((count) =>
+ {
+ countResults[thisQueryId] = count;
+ setCountResults(countResults);
+ setReceivedCountTimestamp(new Date());
+ });
- const results = await qController.query(
- tableName,
- qFilter,
- rowsPerPage,
- pageNumber * rowsPerPage,
- )
+ qController.query(tableName, qFilter, rowsPerPage, pageNumber * rowsPerPage).then((results) =>
+ {
+ console.log(`Received results for query ${thisQueryId}`);
+ queryResults[thisQueryId] = results;
+ setQueryResults(queryResults);
+ setReceivedQueryTimestamp(new Date());
+ })
.catch((error) =>
{
- if (error.message)
+ if (error && error.message)
{
setAlertContent(error.message);
}
- else
+ else if(error && error.response && error.response.data && error.response.data.error)
{
setAlertContent(error.response.data.error);
}
+ else
+ {
+ setAlertContent("Unexpected error running query");
+ console.log(error);
+ }
throw error;
});
+ })();
+ }
- const fields = [...tableMetaData.fields.values()];
- const rows = [] as any[];
- results.forEach((record) =>
+ ///////////////////////////
+ // display count results //
+ ///////////////////////////
+ useEffect(() =>
+ {
+ if (countResults[latestQueryId] === null)
+ {
+ ///////////////////////////////////////////////
+ // see same idea in displaying query results //
+ ///////////////////////////////////////////////
+ console.log(`No count results for id ${latestQueryId}...`);
+ return;
+ }
+ setTotalRecords(countResults[latestQueryId]);
+ delete countResults[latestQueryId];
+ }, [receivedCountTimestamp]);
+
+ ///////////////////////////
+ // display query results //
+ ///////////////////////////
+ useEffect(() =>
+ {
+ if(!queryResults[latestQueryId])
+ {
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // to avoid showing results from an "older" query (e.g., one that was slow, and returned //
+ // AFTER a newer one) only ever show results here for the latestQueryId that was issued. //
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ console.log(`No query results for id ${latestQueryId}...`);
+ return;
+ }
+
+ console.log(`Outputting results for query ${latestQueryId}...`);
+ const results = queryResults[latestQueryId];
+ delete queryResults[latestQueryId];
+
+ const fields = [...tableMetaData.fields.values()];
+ const rows = [] as any[];
+ results.forEach((record: QRecord) =>
+ {
+ const row: any = {};
+ fields.forEach((field) =>
{
- const row: any = {};
- fields.forEach((field) =>
- {
- row[field.name] = QValueUtils.getDisplayValue(field, record);
- });
-
- rows.push(row);
+ row[field.name] = QValueUtils.getDisplayValue(field, record);
});
- const sortedKeys: string[] = [];
+ rows.push(row);
+ });
- for (let i = 0; i < tableMetaData.sections.length; i++)
+ const sortedKeys: string[] = [];
+
+ for (let i = 0; i < tableMetaData.sections.length; i++)
+ {
+ const section = tableMetaData.sections[i];
+ for (let j = 0; j < section.fieldNames.length; j++)
{
- const section = tableMetaData.sections[i];
- for (let j = 0; j < section.fieldNames.length; j++)
+ sortedKeys.push(section.fieldNames[j]);
+ }
+ }
+
+ const columns = [] as GridColDef[];
+ sortedKeys.forEach((key) =>
+ {
+ const field = tableMetaData.fields.get(key);
+
+ let columnType = "string";
+ let columnWidth = 200;
+
+ if (!field.possibleValueSourceName)
+ {
+ switch (field.type)
{
- sortedKeys.push(section.fieldNames[j]);
+ case QFieldType.DECIMAL:
+ case QFieldType.INTEGER:
+ columnType = "number";
+ columnWidth = 100;
+
+ if (key === tableMetaData.primaryKeyField && field.label.length < 3)
+ {
+ columnWidth = 75;
+ }
+
+ break;
+ case QFieldType.DATE:
+ columnType = "date";
+ columnWidth = 100;
+ break;
+ case QFieldType.DATE_TIME:
+ columnType = "dateTime";
+ columnWidth = 200;
+ break;
+ case QFieldType.BOOLEAN:
+ columnType = "boolean";
+ columnWidth = 75;
+ break;
+ default:
+ // noop - leave as string
}
}
- sortedKeys.forEach((key) =>
+ const column = {
+ field: field.name,
+ type: columnType,
+ headerName: field.label,
+ width: columnWidth,
+ renderCell: null as any,
+ };
+
+ if (key === tableMetaData.primaryKeyField)
{
- const field = tableMetaData.fields.get(key);
+ columns.splice(0, 0, column);
+ column.renderCell = (cellValues: any) => (
+ {cellValues.value}
+ );
+ }
+ else
+ {
+ columns.push(column);
+ }
+ });
- let columnType = "string";
- let columnWidth = 200;
-
- if (!field.possibleValueSourceName)
- {
- switch (field.type)
- {
- case QFieldType.DECIMAL:
- case QFieldType.INTEGER:
- columnType = "number";
- columnWidth = 100;
-
- if (key === tableMetaData.primaryKeyField && field.label.length < 3)
- {
- columnWidth = 75;
- }
-
- break;
- case QFieldType.DATE:
- columnType = "date";
- columnWidth = 100;
- break;
- case QFieldType.DATE_TIME:
- columnType = "dateTime";
- columnWidth = 200;
- break;
- case QFieldType.BOOLEAN:
- columnType = "boolean";
- columnWidth = 75;
- break;
- default:
- // noop - leave as string
- }
- }
-
- const column = {
- field: field.name,
- type: columnType,
- headerName: field.label,
- width: columnWidth,
- renderCell: null as any,
- };
-
- if (key === tableMetaData.primaryKeyField)
- {
- columns.splice(0, 0, column);
- column.renderCell = (cellValues: any) => (
- {cellValues.value}
- );
- }
- else
- {
- columns.push(column);
- }
- });
-
- setColumns(columns);
- setRows(rows);
- setLoading(false);
- forceUpdate();
- })();
- };
+ setColumns(columns);
+ setRows(rows);
+ setLoading(false);
+ forceUpdate();
+ }, [receivedQueryTimestamp]);
const handlePageChange = (page: number) =>
{
@@ -470,8 +534,6 @@ function EntityList({table}: Props): JSX.Element
format: string;
}
- // todo - figure out what's up here...
- // eslint-disable-next-line react/no-unstable-nested-components
function ExportMenuItem(props: QExportMenuItemProps)
{
const {format, hideMenu} = props;
@@ -602,10 +664,22 @@ function EntityList({table}: Props): JSX.Element
};
// @ts-ignore
- const defaultLabelDisplayedRows = ({from, to, count}) => `Showing ${from.toLocaleString()} to ${to.toLocaleString()} of ${count !== -1 ? `${count.toLocaleString()} records` : `more than ${to.toLocaleString()} records`}`;
+ const defaultLabelDisplayedRows = ({from, to, count}) =>
+ {
+ if(count !== null && count !== undefined)
+ {
+ if(count === 0)
+ {
+ return ("No rows");
+ }
+ return (`Showing ${from.toLocaleString()} to ${to.toLocaleString()} of ${count !== -1 ? `${count.toLocaleString()} records` : `more than ${to.toLocaleString()} records`}`);
+ }
+ else
+ {
+ return ("Counting records...");
+ }
+ }
- // todo - figure out what's up here...
- // eslint-disable-next-line react/no-unstable-nested-components
function CustomPagination()
{
return (
@@ -622,8 +696,6 @@ function EntityList({table}: Props): JSX.Element
);
}
- // todo - figure out what's up here...
- // eslint-disable-next-line react/no-unstable-nested-components
function Loading()
{
return (
@@ -631,8 +703,6 @@ function EntityList({table}: Props): JSX.Element
);
}
- // todo - figure out what's up here...
- // eslint-disable-next-line react/no-unstable-nested-components
function CustomToolbar()
{
return (