diff --git a/package.json b/package.json index f75f7ef..d20632d 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@fullcalendar/interaction": "5.10.0", "@fullcalendar/react": "5.10.0", "@fullcalendar/timegrid": "5.10.0", - "@kingsrook/qqq-frontend-core": "1.0.30", + "@kingsrook/qqq-frontend-core": "1.0.31", "@mui/icons-material": "5.4.1", "@mui/material": "5.4.1", "@mui/styled-engine": "5.4.1", @@ -75,7 +75,7 @@ "geff-ham": "rm -rf node_modules/ && rm -rf package-lock.json && npm install --legacy-peer-deps && npm start", "install-legacy-peer-deps": "npm install --legacy-peer-deps", "prepublishOnly": "tsc -p ./ --outDir lib/", - "start": "react-scripts start", + "start": "BROWSER=none react-scripts start", "test": "react-scripts test", "cypress:open": "cypress open" }, diff --git a/src/qqq/components/EntityForm/index.tsx b/src/qqq/components/EntityForm/index.tsx index 8f6493c..06616e8 100644 --- a/src/qqq/components/EntityForm/index.tsx +++ b/src/qqq/components/EntityForm/index.tsx @@ -19,6 +19,7 @@ * along with this program. If not, see . */ +import {Capability} from "@kingsrook/qqq-frontend-core/lib/model/metaData/Capability"; import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData"; import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; @@ -73,6 +74,8 @@ function EntityForm({table, id}: Props): JSX.Element const [tableSections, setTableSections] = useState(null as QTableSection[]); const [, forceUpdate] = useReducer((x) => x + 1, 0); + const [noCapabilityError, setNoCapabilityError] = useState(null as string); + const {pageHeader, setPageHeader} = useContext(QContext); const navigate = useNavigate(); @@ -140,11 +143,21 @@ function EntityForm({table, id}: Props): JSX.Element }); setFormValues(formValues); + + if(!tableMetaData.capabilities.has(Capability.TABLE_UPDATE)) + { + setNoCapabilityError("You may not edit records in this table"); + } } else { setFormTitle(`Creating New ${tableMetaData?.label}`); setPageHeader(`Creating New ${tableMetaData?.label}`); + + if(!tableMetaData.capabilities.has(Capability.TABLE_INSERT)) + { + setNoCapabilityError("You may not create records in this table"); + } } setInitialValues(initialValues); @@ -168,6 +181,11 @@ function EntityForm({table, id}: Props): JSX.Element const section = tableSections[i]; const sectionDynamicFormFields: any[] = []; + if(section.isHidden) + { + continue; + } + for (let j = 0; j < section.fieldNames.length; j++) { const fieldName = section.fieldNames[j]; @@ -277,6 +295,19 @@ function EntityForm({table, id}: Props): JSX.Element const formId = id != null ? `edit-${tableMetaData?.name}-form` : `create-${tableMetaData?.name}-form`; + if(noCapabilityError) + { + return + + + + {noCapabilityError} + + + + ; + } + return ( diff --git a/src/qqq/components/QButtons/index.tsx b/src/qqq/components/QButtons/index.tsx index 489686b..b813ea9 100644 --- a/src/qqq/components/QButtons/index.tsx +++ b/src/qqq/components/QButtons/index.tsx @@ -71,7 +71,7 @@ interface QDeleteButtonProps export function QDeleteButton({onClickHandler}: QDeleteButtonProps): JSX.Element { return ( - + delete}> Delete @@ -82,7 +82,7 @@ export function QDeleteButton({onClickHandler}: QDeleteButtonProps): JSX.Element export function QEditButton(): JSX.Element { return ( - + edit}> Edit diff --git a/src/qqq/components/QRecordSidebar/index.tsx b/src/qqq/components/QRecordSidebar/index.tsx index a15a61f..a404978 100644 --- a/src/qqq/components/QRecordSidebar/index.tsx +++ b/src/qqq/components/QRecordSidebar/index.tsx @@ -59,6 +59,11 @@ function QRecordSidebar({tableSections, widgetMetaDataList, light, stickyTop}: P const sidebarEntries = [] as SidebarEntry[]; tableSections && tableSections.forEach((section, index) => { + if(section.isHidden) + { + return; + } + if (index === 1 && widgetMetaDataList) { widgetMetaDataList.forEach((widget) => diff --git a/src/qqq/pages/entity-list/index.tsx b/src/qqq/pages/entity-list/index.tsx index 665ddd6..bdb9e0d 100644 --- a/src/qqq/pages/entity-list/index.tsx +++ b/src/qqq/pages/entity-list/index.tsx @@ -20,6 +20,7 @@ */ import {AdornmentType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/AdornmentType"; +import {Capability} from "@kingsrook/qqq-frontend-core/lib/model/metaData/Capability"; 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"; @@ -584,9 +585,10 @@ function EntityList({table, launchProcess}: Props): JSX.Element const row: any = {}; fields.forEach((field) => { - const value = QValueUtils.getDisplayValue(field, record); + const value = QValueUtils.getDisplayValue(field, record, "query"); if (typeof value !== "string") { + console.log(`Need to render [${field.name}]`); columnsToRender[field.name] = true; } row[field.name] = value; @@ -1146,18 +1148,27 @@ function EntityList({table, launchProcess}: Props): JSX.Element onClose={closeActionsMenu} keepMounted > - - library_add - Bulk Load - - - edit - Bulk Edit - - - delete - Bulk Delete - + { + table.capabilities.has(Capability.TABLE_INSERT) && + + library_add + Bulk Load + + } + { + table.capabilities.has(Capability.TABLE_UPDATE) && + + edit + Bulk Edit + + } + { + table.capabilities.has(Capability.TABLE_DELETE) && + + delete + Bulk Delete + + } {tableProcesses.length > 0 && } {tableProcesses.map((process) => ( processClicked(process)}> @@ -1165,6 +1176,13 @@ function EntityList({table, launchProcess}: Props): JSX.Element {process.label} ))} + { + tableProcesses.length == 0 && !table.capabilities.has(Capability.TABLE_INSERT) && !table.capabilities.has(Capability.TABLE_UPDATE) && !table.capabilities.has(Capability.TABLE_DELETE) && + + block + No actions available + + } ); @@ -1226,7 +1244,10 @@ function EntityList({table, launchProcess}: Props): JSX.Element {renderActionsMenu} - + { + table.capabilities.has(Capability.TABLE_INSERT) && + + } @@ -1244,6 +1265,7 @@ function EntityList({table, launchProcess}: Props): JSX.Element disableSelectionOnClick autoHeight rows={rows} + // getRowHeight={() => "auto"} // maybe nice? wraps values in cells... columns={columnsModel} rowBuffer={10} rowCount={totalRecords === null ? 0 : totalRecords} diff --git a/src/qqq/pages/entity-view/EntityDeveloperView.tsx b/src/qqq/pages/entity-view/EntityDeveloperView.tsx index 5e9126e..2da31f1 100644 --- a/src/qqq/pages/entity-view/EntityDeveloperView.tsx +++ b/src/qqq/pages/entity-view/EntityDeveloperView.tsx @@ -423,7 +423,7 @@ function EntityDeveloperView({table}: Props): JSX.Element { - associatedScripts.map((object) => + associatedScripts && associatedScripts.map((object) => { let fieldName = object.associatedScript?.fieldName; let field = tableMetaData.fields.get(fieldName); diff --git a/src/qqq/pages/entity-view/EntityView.tsx b/src/qqq/pages/entity-view/EntityView.tsx index c182d8d..c552cc2 100644 --- a/src/qqq/pages/entity-view/EntityView.tsx +++ b/src/qqq/pages/entity-view/EntityView.tsx @@ -20,6 +20,7 @@ */ import {QException} from "@kingsrook/qqq-frontend-core/lib/exceptions/QException"; +import {Capability} from "@kingsrook/qqq-frontend-core/lib/model/metaData/Capability"; import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection"; @@ -234,6 +235,11 @@ function EntityView({table, launchProcess}: Props): JSX.Element for (let i = 0; i < tableSections.length; i++) { const section = tableSections[i]; + if(section.isHidden) + { + continue; + } + sectionFieldElements.set( section.name, @@ -244,7 +250,7 @@ function EntityView({table, launchProcess}: Props): JSX.Element {tableMetaData.fields.get(fieldName).label}: - {QValueUtils.getDisplayValue(tableMetaData.fields.get(fieldName), record)} + {QValueUtils.getDisplayValue(tableMetaData.fields.get(fieldName), record, "view")} )) @@ -313,27 +319,33 @@ function EntityView({table, launchProcess}: Props): JSX.Element onClose={closeActionsMenu} keepMounted > - navigate("edit")}> - edit - Edit - - { - setActionsMenu(null); - handleClickDeleteButton(); - }} - > - delete - Delete - - {tableProcesses.length > 0 && } + table.capabilities.has(Capability.TABLE_UPDATE) && + navigate("edit")}> + edit + Edit + + } + { + table.capabilities.has(Capability.TABLE_DELETE) && + + { + setActionsMenu(null); + handleClickDeleteButton(); + }} + > + delete + Delete + + } + {tableProcesses.length > 0 && (table.capabilities.has(Capability.TABLE_UPDATE) || table.capabilities.has(Capability.TABLE_DELETE)) && } {tableProcesses.map((process) => ( processClicked(process)}> {process.iconName ?? "arrow_forward"} {process.label} ))} - + {tableProcesses.length > 0 && } navigate("dev")}> data_object Developer Mode @@ -433,8 +445,12 @@ function EntityView({table, launchProcess}: Props): JSX.Element )) : null} - - + { + table.capabilities.has(Capability.TABLE_DELETE) && + } + { + table.capabilities.has(Capability.TABLE_UPDATE) && + } diff --git a/src/qqq/pages/process-run/components/QValidationReview.tsx b/src/qqq/pages/process-run/components/QValidationReview.tsx index 8932061..d252f2a 100644 --- a/src/qqq/pages/process-run/components/QValidationReview.tsx +++ b/src/qqq/pages/process-run/components/QValidationReview.tsx @@ -253,7 +253,7 @@ function QValidationReview({ {" "}   {" "} - {QValueUtils.getDisplayValue(field, previewRecords[previewRecordIndex])} + {QValueUtils.getDisplayValue(field, previewRecords[previewRecordIndex], "view")} )) } diff --git a/src/qqq/pages/process-run/index.tsx b/src/qqq/pages/process-run/index.tsx index 601c9ff..4761d55 100644 --- a/src/qqq/pages/process-run/index.tsx +++ b/src/qqq/pages/process-run/index.tsx @@ -362,8 +362,11 @@ function ProcessRun({process, defaultProcessValues, isModal, recordIds, closeMod {localTableSections.map((section: QTableSection, index: number) => { const name = section.name - console.log(formData); - console.log(section.fieldNames); + + if(section.isHidden) + { + return ; + } const sectionFormFields = {}; for(let i = 0; i - {QValueUtils.getValueForDisplay(field, processValues[field.name])} + {QValueUtils.getValueForDisplay(field, processValues[field.name], "view")} ))} diff --git a/src/qqq/utils/QValueUtils.tsx b/src/qqq/utils/QValueUtils.tsx index 065d134..038d5f7 100644 --- a/src/qqq/utils/QValueUtils.tsx +++ b/src/qqq/utils/QValueUtils.tsx @@ -25,8 +25,9 @@ import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QField import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance"; import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord"; import "datejs"; -import {Chip, Icon} from "@mui/material"; +import {Chip, Icon, Typography} from "@mui/material"; import React, {Fragment} from "react"; +import AceEditor from "react-ace"; import {Link} from "react-router-dom"; import QClient from "qqq/utils/QClient"; @@ -66,19 +67,19 @@ class QValueUtils ** When you have a field, and a record - call this method to get a string or ** element back to display the field's value. *******************************************************************************/ - public static getDisplayValue(field: QFieldMetaData, record: QRecord): string | JSX.Element + public static getDisplayValue(field: QFieldMetaData, record: QRecord, usage: "view" | "query" = "view"): string | JSX.Element { const displayValue = record.displayValues ? record.displayValues.get(field.name) : undefined; const rawValue = record.values ? record.values.get(field.name) : undefined; - return QValueUtils.getValueForDisplay(field, rawValue, displayValue); + return QValueUtils.getValueForDisplay(field, rawValue, displayValue, usage); } /******************************************************************************* ** When you have a field and a value (either just a raw value, or a raw and ** display value), call this method to get a string Element to display. *******************************************************************************/ - public static getValueForDisplay(field: QFieldMetaData, rawValue: any, displayValue: any = rawValue): string | JSX.Element + public static getValueForDisplay(field: QFieldMetaData, rawValue: any, displayValue: any = rawValue, usage: "view" | "query" = "view"): string | JSX.Element { if (field.hasAdornment(AdornmentType.LINK)) { @@ -141,6 +142,28 @@ class QValueUtils return (); } + if (field.hasAdornment(AdornmentType.CODE_EDITOR)) + { + if(usage === "view") + { + return (); + } + else + { + return rawValue; + } + } + return (QValueUtils.getUnadornedValueForDisplay(field, rawValue, displayValue)); } @@ -227,6 +250,11 @@ class QValueUtils public static breakTextIntoLines(value: string): JSX.Element { + if(!value) + { + return ; + } + return ( {value.split(/\n/).map((value: string, index: number) => (