{currentVersionId == version?.values?.get("id") && }
{version.values.get("commitMessage")}
diff --git a/src/qqq/components/widgets/misc/ScriptViewer.tsx b/src/qqq/components/widgets/misc/ScriptViewer.tsx
index 8b4a942..09995b1 100644
--- a/src/qqq/components/widgets/misc/ScriptViewer.tsx
+++ b/src/qqq/components/widgets/misc/ScriptViewer.tsx
@@ -314,7 +314,7 @@ export default function ScriptViewer({scriptId, associatedScriptTableName, assoc
primaryTypographyProps={{fontSize: "1rem"}}
secondaryTypographyProps={{fontSize: ".85rem"}}
primary={
-
+
{scriptRecord.values.get("currentScriptRevisionId") == version?.values?.get("id") && }
{version.values.get("commitMessage")}
diff --git a/src/qqq/pages/processes/ProcessRun.tsx b/src/qqq/pages/processes/ProcessRun.tsx
index 36973a1..2b6e33a 100644
--- a/src/qqq/pages/processes/ProcessRun.tsx
+++ b/src/qqq/pages/processes/ProcessRun.tsx
@@ -992,6 +992,10 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
}
setQJobRunning(null);
}
+ else
+ {
+ console.warn(`Process response was not of an expected type (need an npm clean?) ${JSON.stringify(lastProcessResponse)}`);
+ }
}
}, [lastProcessResponse]);
@@ -1150,6 +1154,11 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
}
}
+ if(tableMetaData)
+ {
+ queryStringPairsForInit.push(`tableName=${tableMetaData.name}`)
+ }
+
try
{
const processResponse = await Client.getInstance().processInit(processName, queryStringPairsForInit.join("&"));
diff --git a/src/qqq/pages/records/query/RecordQuery.tsx b/src/qqq/pages/records/query/RecordQuery.tsx
index 35c9cc6..6767970 100644
--- a/src/qqq/pages/records/query/RecordQuery.tsx
+++ b/src/qqq/pages/records/query/RecordQuery.tsx
@@ -71,6 +71,7 @@ import DataGridUtils from "qqq/utils/DataGridUtils";
import Client from "qqq/utils/qqq/Client";
import FilterUtils from "qqq/utils/qqq/FilterUtils";
import ProcessUtils from "qqq/utils/qqq/ProcessUtils";
+import TableUtils from "qqq/utils/qqq/TableUtils";
import ValueUtils from "qqq/utils/qqq/ValueUtils";
const CURRENT_SAVED_FILTER_ID_LOCAL_STORAGE_KEY_ROOT = "qqq.currentSavedFilterId";
@@ -628,6 +629,8 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
let models = await FilterUtils.determineFilterAndSortModels(qController, tableMetaData, null, searchParams, filterLocalStorageKey, sortLocalStorageKey);
setFilterModel(models.filter);
setColumnSortModel(models.sort);
+ setWarningAlert(models.warning);
+
setQueryFilter(FilterUtils.buildQFilterFromGridFilter(tableMetaData, models.filter, models.sort, rowsPerPage));
return;
}
@@ -708,16 +711,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
if (tableMetaData?.exposedJoins)
{
const visibleJoinTables = getVisibleJoinTables();
-
- queryJoins = [];
- for (let i = 0; i < tableMetaData.exposedJoins.length; i++)
- {
- const join = tableMetaData.exposedJoins[i];
- if (visibleJoinTables.has(join.joinTable.name))
- {
- queryJoins.push(new QueryJoin(join.joinTable.name, true, "LEFT"));
- }
- }
+ queryJoins = TableUtils.getQueryJoins(tableMetaData, visibleJoinTables);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1401,6 +1395,8 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
const models = await FilterUtils.determineFilterAndSortModels(qController, tableMetaData, qRecord.values.get("filterJson"), null, null, null);
handleFilterChange(models.filter);
handleSortChange(models.sort, models.filter);
+ setWarningAlert(models.warning);
+
localStorage.setItem(currentSavedFilterLocalStorageKey, selectedSavedFilterId.toString());
}
else
@@ -1432,35 +1428,13 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
return (qRecord);
}
- const getFieldAndTable = (fieldName: string): [QFieldMetaData, QTableMetaData] =>
- {
- if(fieldName.indexOf(".") > -1)
- {
- const nameParts = fieldName.split(".", 2);
- for (let i = 0; i < tableMetaData?.exposedJoins?.length; i++)
- {
- const join = tableMetaData?.exposedJoins[i];
- if(join?.joinTable.name == nameParts[0])
- {
- return ([join.joinTable.fields.get(nameParts[1]), join.joinTable]);
- }
- }
- }
- else
- {
- return ([tableMetaData.fields.get(fieldName), tableMetaData]);
- }
-
- return (null);
- }
-
const copyColumnValues = async (column: GridColDef) =>
{
let data = "";
let counter = 0;
if (latestQueryResults && latestQueryResults.length)
{
- let [qFieldMetaData, fieldTable] = getFieldAndTable(column.field);
+ let [qFieldMetaData, fieldTable] = TableUtils.getFieldAndTable(tableMetaData, column.field);
for (let i = 0; i < latestQueryResults.length; i++)
{
let record = latestQueryResults[i] as QRecord;
@@ -1490,7 +1464,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
setFilterForColumnStats(buildQFilter(tableMetaData, filterModel));
setColumnStatsFieldName(column.field);
- const [field, fieldTable] = getFieldAndTable(column.field);
+ const [field, fieldTable] = TableUtils.getFieldAndTable(tableMetaData, column.field);
setColumnStatsField(field);
setColumnStatsFieldTableName(fieldTable.name);
};
@@ -1963,7 +1937,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
{
(warningAlert) ? (
- setWarningAlert(null)}>{warningAlert}
+ warning} sx={{mb: 3}} onClose={() => setWarningAlert(null)}>{warningAlert}
) : null
}
diff --git a/src/qqq/pages/records/view/RecordView.tsx b/src/qqq/pages/records/view/RecordView.tsx
index e04fcdd..c9124e2 100644
--- a/src/qqq/pages/records/view/RecordView.tsx
+++ b/src/qqq/pages/records/view/RecordView.tsx
@@ -27,6 +27,7 @@ import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QT
import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection";
import {QTableVariant} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableVariant";
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
+import {QueryJoin} from "@kingsrook/qqq-frontend-core/lib/model/query/QueryJoin";
import {Alert, Typography} from "@mui/material";
import Avatar from "@mui/material/Avatar";
import Box from "@mui/material/Box";
@@ -103,7 +104,7 @@ function RecordView({table, launchProcess}: Props): JSX.Element
const [allTableProcesses, setAllTableProcesses] = useState([] as QProcessMetaData[]);
const [actionsMenu, setActionsMenu] = useState(null);
const [notFoundMessage, setNotFoundMessage] = useState(null as string);
- const [errorMessage, setErrorMessage] = useState(null as string)
+ const [errorMessage, setErrorMessage] = useState(null as string);
const [successMessage, setSuccessMessage] = useState(null as string);
const [warningMessage, setWarningMessage] = useState(null as string);
const [activeModalProcess, setActiveModalProcess] = useState(null as QProcessMetaData);
@@ -325,6 +326,31 @@ function RecordView({table, launchProcess}: Props): JSX.Element
reload();
}, [location.pathname, location.hash]);
+ const getVisibleJoinTables = (tableMetaData: QTableMetaData): Set
=>
+ {
+ const visibleJoinTables = new Set();
+
+ for (let i = 0; i < tableMetaData?.sections.length; i++)
+ {
+ const section = tableMetaData?.sections[i];
+ if (section.isHidden || !section.fieldNames || !section.fieldNames.length)
+ {
+ continue;
+ }
+
+ section.fieldNames.forEach((fieldName) =>
+ {
+ const [field, tableForField] = TableUtils.getFieldAndTable(tableMetaData, fieldName);
+ if(tableForField && tableForField.name != tableMetaData.name)
+ {
+ visibleJoinTables.add(tableForField.name);
+ }
+ })
+ }
+
+ return (visibleJoinTables);
+ };
+
if (!asyncLoadInited)
{
setAsyncLoadInited(true);
@@ -368,13 +394,20 @@ function RecordView({table, launchProcess}: Props): JSX.Element
setActiveModalProcess(launchingProcess);
}
+ let queryJoins: QueryJoin[] = null;
+ const visibleJoinTables = getVisibleJoinTables(tableMetaData);
+ if(visibleJoinTables.size > 0)
+ {
+ queryJoins = TableUtils.getQueryJoins(tableMetaData, visibleJoinTables);
+ }
+
/////////////////////
// load the record //
/////////////////////
let record: QRecord;
try
{
- record = await qController.get(tableName, id, tableVariant);
+ record = await qController.get(tableName, id, tableVariant, null, queryJoins);
setRecord(record);
}
catch (e)
@@ -465,17 +498,22 @@ function RecordView({table, launchProcess}: Props): JSX.Element
const fields = (
{
- section.fieldNames.map((fieldName: string) => (
-
-
- {tableMetaData.fields.get(fieldName).label}:
-
-
-
- {ValueUtils.getDisplayValue(tableMetaData.fields.get(fieldName), record, "view")}
-
-
- ))
+ section.fieldNames.map((fieldName: string) =>
+ {
+ let [field, tableForField] = TableUtils.getFieldAndTable(tableMetaData, fieldName);
+ let label = field.label;
+ return (
+
+
+ {label}:
+
+
+
+ {ValueUtils.getDisplayValue(field, record, "view", fieldName)}
+
+
+ )
+ })
}
);
diff --git a/src/qqq/utils/qqq/FilterUtils.ts b/src/qqq/utils/qqq/FilterUtils.ts
index eeb86b9..6fbb489 100644
--- a/src/qqq/utils/qqq/FilterUtils.ts
+++ b/src/qqq/utils/qqq/FilterUtils.ts
@@ -31,6 +31,7 @@ import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilt
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
import {ThisOrLastPeriodExpression} from "@kingsrook/qqq-frontend-core/lib/model/query/ThisOrLastPeriodExpression";
import {GridFilterItem, GridFilterModel, GridLinkOperator, GridSortItem} from "@mui/x-data-grid-pro";
+import TableUtils from "qqq/utils/qqq/TableUtils";
import ValueUtils from "qqq/utils/qqq/ValueUtils";
const CURRENT_SAVED_FILTER_ID_LOCAL_STORAGE_KEY_ROOT = "qqq.currentSavedFilterId";
@@ -375,10 +376,11 @@ class FilterUtils
** Get the default filter to use on the page - either from given filter string, query string param, or
** local storage, or a default (empty).
*******************************************************************************/
- public static async determineFilterAndSortModels(qController: QController, tableMetaData: QTableMetaData, filterString: string, searchParams: URLSearchParams, filterLocalStorageKey: string, sortLocalStorageKey: string): Promise<{ filter: GridFilterModel, sort: GridSortItem[] }>
+ public static async determineFilterAndSortModels(qController: QController, tableMetaData: QTableMetaData, filterString: string, searchParams: URLSearchParams, filterLocalStorageKey: string, sortLocalStorageKey: string): Promise<{ filter: GridFilterModel, sort: GridSortItem[], warning: string }>
{
let defaultFilter = {items: []} as GridFilterModel;
let defaultSort = [] as GridSortItem[];
+ let warningParts = [] as string[];
if (tableMetaData && tableMetaData.fields !== undefined)
{
@@ -396,30 +398,11 @@ class FilterUtils
for (let i = 0; i < qQueryFilter?.criteria?.length; i++)
{
const criteria = qQueryFilter.criteria[i];
- 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);
- }
-
+ let [field, fieldTable] = TableUtils.getFieldAndTable(tableMetaData, criteria.fieldName);
if (field == null)
{
console.log("Couldn't find field for filter: " + criteria.fieldName);
+ warningParts.push("Your filter contained an unrecognized field name: " + criteria.fieldName)
continue;
}
@@ -500,7 +483,7 @@ class FilterUtils
localStorage.setItem(sortLocalStorageKey, JSON.stringify(defaultSort));
}
- return ({filter: defaultFilter, sort: defaultSort});
+ return ({filter: defaultFilter, sort: defaultSort, warning: warningParts.length > 0 ? "Warning: " + warningParts.join("; ") : ""});
}
catch (e)
{
@@ -551,7 +534,7 @@ class FilterUtils
});
}
- return ({filter: defaultFilter, sort: defaultSort});
+ return ({filter: defaultFilter, sort: defaultSort, warning: warningParts.length > 0 ? "Warning: " + warningParts.join("; ") : ""});
}
diff --git a/src/qqq/utils/qqq/TableUtils.ts b/src/qqq/utils/qqq/TableUtils.ts
index 444afa8..dd0f6eb 100644
--- a/src/qqq/utils/qqq/TableUtils.ts
+++ b/src/qqq/utils/qqq/TableUtils.ts
@@ -19,8 +19,10 @@
* along with this program. If not, see .
*/
+import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection";
+import {QueryJoin} from "@kingsrook/qqq-frontend-core/lib/model/query/QueryJoin";
/*******************************************************************************
** Utility class for working with QQQ Tables
@@ -28,7 +30,6 @@ import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTa
*******************************************************************************/
class TableUtils
{
-
/*******************************************************************************
**
*******************************************************************************/
@@ -85,6 +86,61 @@ class TableUtils
})]);
}
}
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static getFieldAndTable(tableMetaData: QTableMetaData, fieldName: string): [QFieldMetaData, QTableMetaData]
+ {
+ if (fieldName.indexOf(".") > -1)
+ {
+ const nameParts = fieldName.split(".", 2);
+ for (let i = 0; i < tableMetaData?.exposedJoins?.length; i++)
+ {
+ const join = tableMetaData?.exposedJoins[i];
+ if (join?.joinTable.name == nameParts[0])
+ {
+ return ([join.joinTable.fields.get(nameParts[1]), join.joinTable]);
+ }
+ }
+ }
+ else
+ {
+ return ([tableMetaData.fields.get(fieldName), tableMetaData]);
+ }
+
+ return (null);
+ }
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ public static getQueryJoins(tableMetaData: QTableMetaData, visibleJoinTables: Set): QueryJoin[]
+ {
+ const queryJoins = [];
+ for (let i = 0; i < tableMetaData.exposedJoins.length; i++)
+ {
+ const join = tableMetaData.exposedJoins[i];
+ if (visibleJoinTables.has(join.joinTable.name))
+ {
+ let joinName = null;
+ if (join.joinPath && join.joinPath.length == 1 && join.joinPath[0].name)
+ {
+ joinName = join.joinPath[0].name;
+ }
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // todo - what about a join with a longer path? it would be nice to pass such joinNames through there too, //
+ // but what, that would actually be multiple queryJoins? needs a fair amount of thought. //
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ queryJoins.push(new QueryJoin(join.joinTable.name, true, "LEFT", null, null, joinName));
+ }
+ }
+
+ return queryJoins;
+ }
+
+
}
export default TableUtils;