mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 05:10:45 +00:00
Update to not show results from previous queries or counts
This commit is contained in:
@ -22,6 +22,7 @@
|
|||||||
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
||||||
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 {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||||
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
|
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
|
||||||
import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy";
|
import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy";
|
||||||
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
|
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 [pinnedColumns, setPinnedColumns] = useState({left: ["__check__", "id"]});
|
||||||
const instance = useRef({timer: null});
|
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 [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||||
|
|
||||||
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
|
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), //
|
// 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 //
|
||||||
// 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 //
|
// return here ane wait for the next 'turn' to allow doing the actual query //
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if (!defaultFilterLoaded)
|
if (!defaultFilterLoaded)
|
||||||
@ -210,6 +219,7 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setTableMetaData(tableMetaData);
|
setTableMetaData(tableMetaData);
|
||||||
|
setTableLabel(tableMetaData.label);
|
||||||
if (columnSortModel.length === 0)
|
if (columnSortModel.length === 0)
|
||||||
{
|
{
|
||||||
columnSortModel.push({
|
columnSortModel.push({
|
||||||
@ -222,121 +232,175 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
|
|
||||||
const qFilter = buildQFilter();
|
const qFilter = buildQFilter();
|
||||||
|
|
||||||
const count = await qController.count(tableName, qFilter);
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
setTotalRecords(count);
|
// assign a new query id to the query being issued here. then run both the count & query async //
|
||||||
setTableLabel(tableMetaData.label);
|
// 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(
|
qController.query(tableName, qFilter, rowsPerPage, pageNumber * rowsPerPage).then((results) =>
|
||||||
tableName,
|
{
|
||||||
qFilter,
|
console.log(`Received results for query ${thisQueryId}`);
|
||||||
rowsPerPage,
|
queryResults[thisQueryId] = results;
|
||||||
pageNumber * rowsPerPage,
|
setQueryResults(queryResults);
|
||||||
)
|
setReceivedQueryTimestamp(new Date());
|
||||||
|
})
|
||||||
.catch((error) =>
|
.catch((error) =>
|
||||||
{
|
{
|
||||||
if (error.message)
|
if (error && error.message)
|
||||||
{
|
{
|
||||||
setAlertContent(error.message);
|
setAlertContent(error.message);
|
||||||
}
|
}
|
||||||
else
|
else if(error && error.response && error.response.data && error.response.data.error)
|
||||||
{
|
{
|
||||||
setAlertContent(error.response.data.error);
|
setAlertContent(error.response.data.error);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setAlertContent("Unexpected error running query");
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
const fields = [...tableMetaData.fields.values()];
|
///////////////////////////
|
||||||
const rows = [] as any[];
|
// display count results //
|
||||||
results.forEach((record) =>
|
///////////////////////////
|
||||||
|
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 = {};
|
row[field.name] = QValueUtils.getDisplayValue(field, record);
|
||||||
fields.forEach((field) =>
|
|
||||||
{
|
|
||||||
row[field.name] = QValueUtils.getDisplayValue(field, record);
|
|
||||||
});
|
|
||||||
|
|
||||||
rows.push(row);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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];
|
sortedKeys.push(section.fieldNames[j]);
|
||||||
for (let j = 0; j < section.fieldNames.length; 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) => (
|
||||||
|
<Link to={cellValues.value}>{cellValues.value}</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
columns.push(column);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let columnType = "string";
|
setColumns(columns);
|
||||||
let columnWidth = 200;
|
setRows(rows);
|
||||||
|
setLoading(false);
|
||||||
if (!field.possibleValueSourceName)
|
forceUpdate();
|
||||||
{
|
}, [receivedQueryTimestamp]);
|
||||||
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) => (
|
|
||||||
<Link to={cellValues.value}>{cellValues.value}</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
columns.push(column);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setColumns(columns);
|
|
||||||
setRows(rows);
|
|
||||||
setLoading(false);
|
|
||||||
forceUpdate();
|
|
||||||
})();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePageChange = (page: number) =>
|
const handlePageChange = (page: number) =>
|
||||||
{
|
{
|
||||||
@ -470,8 +534,6 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
format: string;
|
format: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo - figure out what's up here...
|
|
||||||
// eslint-disable-next-line react/no-unstable-nested-components
|
|
||||||
function ExportMenuItem(props: QExportMenuItemProps)
|
function ExportMenuItem(props: QExportMenuItemProps)
|
||||||
{
|
{
|
||||||
const {format, hideMenu} = props;
|
const {format, hideMenu} = props;
|
||||||
@ -602,10 +664,22 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore
|
// @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()
|
function CustomPagination()
|
||||||
{
|
{
|
||||||
return (
|
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()
|
function Loading()
|
||||||
{
|
{
|
||||||
return (
|
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()
|
function CustomToolbar()
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
|
Reference in New Issue
Block a user