column stats checkpoint

This commit is contained in:
2023-03-01 08:38:35 -06:00
parent 968397bcc9
commit f766f17a92
4 changed files with 92 additions and 27 deletions

View File

@ -21,13 +21,17 @@
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData"; import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection";
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 {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
import {TablePagination} from "@mui/material";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import LinearProgress from "@mui/material/LinearProgress";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import {DataGridPro} from "@mui/x-data-grid-pro"; import {DataGridPro} from "@mui/x-data-grid-pro";
import {columnsStateInitializer} from "@mui/x-data-grid/internals"; import FormData from "form-data";
import React, {useEffect, useState} from "react"; import React, {useEffect, useState} from "react";
import DataGridUtils from "qqq/utils/DataGridUtils"; import DataGridUtils from "qqq/utils/DataGridUtils";
import Client from "qqq/utils/qqq/Client"; import Client from "qqq/utils/qqq/Client";
@ -36,16 +40,15 @@ interface Props
{ {
tableMetaData: QTableMetaData; tableMetaData: QTableMetaData;
fieldMetaData: QFieldMetaData; fieldMetaData: QFieldMetaData;
closeModalHandler?: (event: object, reason: string) => void; filter: QQueryFilter;
} }
ColumnStats.defaultProps = { ColumnStats.defaultProps = {
closeModalHandler: null,
}; };
const qController = Client.getInstance(); const qController = Client.getInstance();
function ColumnStats({tableMetaData, fieldMetaData, closeModalHandler}: Props): JSX.Element function ColumnStats({tableMetaData, fieldMetaData, filter}: Props): JSX.Element
{ {
const [statusString, setStatusString] = useState("Calculating statistics..."); const [statusString, setStatusString] = useState("Calculating statistics...");
const [isLoaded, setIsLoaded] = useState(false); const [isLoaded, setIsLoaded] = useState(false);
@ -58,7 +61,12 @@ function ColumnStats({tableMetaData, fieldMetaData, closeModalHandler}: Props):
{ {
(async () => (async () =>
{ {
const processResult = await qController.processRun("tableStats", `tableName=${tableMetaData.name}&fieldName=${fieldMetaData.name}`); const formData = new FormData();
formData.append("tableName", tableMetaData.name);
formData.append("fieldName", fieldMetaData.name);
formData.append("filterJSON", JSON.stringify(filter));
const processResult = await qController.processRun("tableStats", formData);
setStatusString(null) setStatusString(null)
if (processResult instanceof QJobError) if (processResult instanceof QJobError)
{ {
@ -72,15 +80,29 @@ function ColumnStats({tableMetaData, fieldMetaData, closeModalHandler}: Props):
setCountDistinct(result.values.countDistinct); setCountDistinct(result.values.countDistinct);
const valueCounts = [] as QRecord[]; const valueCounts = [] as QRecord[];
result.values.valueCounts.forEach((object: any) => for(let i = 0; i < result.values.valueCounts.length; i++)
{ {
valueCounts.push(new QRecord(object)); valueCounts.push(new QRecord(result.values.valueCounts[i]));
}) }
setValueCounts(valueCounts); setValueCounts(valueCounts);
const fakeTableMetaData = new QTableMetaData({primaryKeyField: "value", fields: {value: fieldMetaData, count: {label: "Count", type: "INTEGER"}}}); const fakeTableMetaData = new QTableMetaData({primaryKeyField: fieldMetaData.name});
fakeTableMetaData.fields = new Map<string, QFieldMetaData>();
fakeTableMetaData.fields.set(fieldMetaData.name, fieldMetaData);
fakeTableMetaData.fields.set("count", new QFieldMetaData({name: "count", label: "Count", type: "INTEGER"}));
fakeTableMetaData.sections = [] as QTableSection[];
fakeTableMetaData.sections.push(new QTableSection({fieldNames: [fieldMetaData.name, "count"]}));
const {rows, columnsToRender} = DataGridUtils.makeRows(valueCounts, fakeTableMetaData); const {rows, columnsToRender} = DataGridUtils.makeRows(valueCounts, fakeTableMetaData);
const columns = DataGridUtils.setupGridColumns(fakeTableMetaData, columnsToRender); const columns = DataGridUtils.setupGridColumns(fakeTableMetaData, columnsToRender);
columns[1].sortComparator = (v1, v2): number =>
{
const n1 = parseInt(v1.replaceAll(",", ""));
const n2 = parseInt(v2.replaceAll(",", ""));
return (n1 - n2);
}
setRows(rows); setRows(rows);
setColumns(columns); setColumns(columns);
@ -89,32 +111,71 @@ function ColumnStats({tableMetaData, fieldMetaData, closeModalHandler}: Props):
})(); })();
}, []); }, []);
// @ts-ignore
const defaultLabelDisplayedRows = ({from, to, count}) =>
{
// todo - not done
return ("Showing stuff");
};
function CustomPagination()
{
return (
<TablePagination
component="div"
page={1}
count={1}
rowsPerPage={1000}
onPageChange={null}
labelDisplayedRows={defaultLabelDisplayedRows}
/>
);
}
function Loading()
{
return (
<LinearProgress color="info" />
);
}
return ( return (
<Box> <Box>
<Box p={3} display="flex" flexDirection="row" justifyContent="space-between" alignItems="flex-start"> <Box p={3} display="flex" flexDirection="row" justifyContent="space-between" alignItems="flex-start">
<Typography variant="h5" pb={3}> <Typography variant="h5" pb={3}>
Column Statistics for {tableMetaData.label} : {fieldMetaData.label} Column Statistics for {tableMetaData.label}: {fieldMetaData.label}
<Typography fontSize={14}> <Typography fontSize={14}>
{statusString} {statusString}
</Typography> </Typography>
</Typography> </Typography>
</Box> </Box>
{ <Box px={3} fontSize="1rem">
isLoaded && <> <div>
<Box sx={{overflow: "auto", height: "calc( 100vh - 19rem )", position: "relative"}} px={3}> <div className="fieldLabel">Distinct Values: </div> <div className="fieldValue">{Number(countDistinct).toLocaleString()}</div>
<b>Distinct Values: </b> {countDistinct.toLocaleString()} </div>
</Box>
<Box sx={{overflow: "auto", height: "calc( 100vh - 19rem )", position: "relative"}} px={3}>
<DataGridPro <DataGridPro
autoHeight components={{LoadingOverlay: Loading, Pagination: CustomPagination}}
rows={rows} rows={rows}
disableSelectionOnClick disableSelectionOnClick
columns={columns} columns={columns}
loading={!isLoaded}
rowBuffer={10} rowBuffer={10}
getRowClassName={(params) => (params.indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd")} getRowClassName={(params) => (params.indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd")}
initialState={{
sorting: {
sortModel: [
{
field: "count",
sort: "desc",
},
],
},
}}
/> />
</Box> </Box>
</>
}
</Box>); </Box>);
} }

View File

@ -169,6 +169,7 @@ 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 [filterForColumnStats, setFilterForColumnStats] = useState(null as QQueryFilter)
const instance = useRef({timer: null}); const instance = useRef({timer: null});
@ -995,6 +996,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
const openColumnStatistics = async (column: GridColDef) => const openColumnStatistics = async (column: GridColDef) =>
{ {
setFilterForColumnStats(buildQFilter(filterModel));
setColumnStatsFieldName(column.field); setColumnStatsFieldName(column.field);
} }
@ -1391,7 +1393,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)} closeModalHandler={closeColumnStats} /> <ColumnStats tableMetaData={tableMetaData} fieldMetaData={tableMetaData?.fields.get(columnStatsFieldName)} 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

@ -350,12 +350,14 @@ input[type="search"]::-webkit-search-results-decoration { display: none; }
color: rgb(52, 71, 103); color: rgb(52, 71, 103);
font-weight: 700; font-weight: 700;
padding-right: .5em; padding-right: .5em;
display: inline;
} }
.fieldValue .fieldValue
{ {
color: rgb(123, 128, 154); color: rgb(123, 128, 154);
font-weight: 400; font-weight: 400;
display: inline;
} }
.fullScreenWidget .fullScreenWidget

View File

@ -56,7 +56,7 @@ export default class DataGridUtils
if(!row["id"]) if(!row["id"])
{ {
row["id"] = row[tableMetaData.primaryKeyField]; row["id"] = record.values.get(tableMetaData.primaryKeyField) ?? row[tableMetaData.primaryKeyField];
} }
rows.push(row); rows.push(row);