mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-21 22:58:43 +00:00
Compare commits
4 Commits
snapshot-f
...
snapshot-f
Author | SHA1 | Date | |
---|---|---|---|
30991cb34e | |||
2fd6272ea3 | |||
b63d74f785 | |||
ff946df461 |
@ -63,7 +63,7 @@ interface Props
|
|||||||
disabledFields: { [key: string]: boolean } | string[];
|
disabledFields: { [key: string]: boolean } | string[];
|
||||||
isCopy?: boolean;
|
isCopy?: boolean;
|
||||||
onSubmitCallback?: (values: any) => void;
|
onSubmitCallback?: (values: any) => void;
|
||||||
overrideHeading?: string
|
overrideHeading?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityForm.defaultProps = {
|
EntityForm.defaultProps = {
|
||||||
@ -100,8 +100,8 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
const [metaData, setMetaData] = useState(null as QInstance);
|
const [metaData, setMetaData] = useState(null as QInstance);
|
||||||
const [record, setRecord] = useState(null as QRecord);
|
const [record, setRecord] = useState(null as QRecord);
|
||||||
const [tableSections, setTableSections] = useState(null as QTableSection[]);
|
const [tableSections, setTableSections] = useState(null as QTableSection[]);
|
||||||
const [renderedWidgetSections, setRenderedWidgetSections] = useState({} as {[name: string]: JSX.Element});
|
const [renderedWidgetSections, setRenderedWidgetSections] = useState({} as { [name: string]: JSX.Element });
|
||||||
const [childListWidgetData, setChildListWidgetData] = useState({} as {[name: string]: ChildRecordListData});
|
const [childListWidgetData, setChildListWidgetData] = useState({} as { [name: string]: ChildRecordListData });
|
||||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||||
|
|
||||||
const [showEditChildForm, setShowEditChildForm] = useState(null as any);
|
const [showEditChildForm, setShowEditChildForm] = useState(null as any);
|
||||||
@ -128,21 +128,26 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const parts = hashParts[i].split("=")
|
const parts = hashParts[i].split("=");
|
||||||
if (parts.length > 1 && parts[0] == "defaultValues")
|
if (parts.length > 1)
|
||||||
{
|
{
|
||||||
defaultValues = JSON.parse(decodeURIComponent(parts[1])) as { [key: string]: any };
|
const name = parts[0].replace(/^#/, "");
|
||||||
|
const value = parts[1];
|
||||||
|
if (name == "defaultValues")
|
||||||
|
{
|
||||||
|
defaultValues = JSON.parse(decodeURIComponent(value)) as { [key: string]: any };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parts.length > 1 && parts[0] == "disabledFields")
|
if (name == "disabledFields")
|
||||||
{
|
{
|
||||||
disabledFields = JSON.parse(decodeURIComponent(parts[1])) as { [key: string]: any };
|
disabledFields = JSON.parse(decodeURIComponent(value)) as { [key: string]: any };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -153,7 +158,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
let defaultValues = widgetData.defaultValuesForNewChildRecords;
|
let defaultValues = widgetData.defaultValuesForNewChildRecords;
|
||||||
|
|
||||||
let disabledFields = widgetData.disabledFieldsForNewChildRecords;
|
let disabledFields = widgetData.disabledFieldsForNewChildRecords;
|
||||||
if(!disabledFields)
|
if (!disabledFields)
|
||||||
{
|
{
|
||||||
disabledFields = widgetData.defaultValuesForNewChildRecords;
|
disabledFields = widgetData.defaultValuesForNewChildRecords;
|
||||||
}
|
}
|
||||||
@ -170,7 +175,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
let defaultValues = widgetData.queryOutput.records[rowIndex].values;
|
let defaultValues = widgetData.queryOutput.records[rowIndex].values;
|
||||||
|
|
||||||
let disabledFields = widgetData.disabledFieldsForNewChildRecords;
|
let disabledFields = widgetData.disabledFieldsForNewChildRecords;
|
||||||
if(!disabledFields)
|
if (!disabledFields)
|
||||||
{
|
{
|
||||||
disabledFields = widgetData.defaultValuesForNewChildRecords;
|
disabledFields = widgetData.defaultValuesForNewChildRecords;
|
||||||
}
|
}
|
||||||
@ -234,16 +239,16 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
const metaData = await qController.loadMetaData();
|
const metaData = await qController.loadMetaData();
|
||||||
const widgetMetaData = metaData.widgets.get(widgetName);
|
const widgetMetaData = metaData.widgets.get(widgetName);
|
||||||
|
|
||||||
const newChildListWidgetData: {[name: string]: ChildRecordListData} = Object.assign({}, childListWidgetData)
|
const newChildListWidgetData: { [name: string]: ChildRecordListData } = Object.assign({}, childListWidgetData);
|
||||||
if(!newChildListWidgetData[widgetName].queryOutput.records)
|
if (!newChildListWidgetData[widgetName].queryOutput.records)
|
||||||
{
|
{
|
||||||
newChildListWidgetData[widgetName].queryOutput.records = [];
|
newChildListWidgetData[widgetName].queryOutput.records = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case "insert":
|
case "insert":
|
||||||
newChildListWidgetData[widgetName].queryOutput.records.push({values: values})
|
newChildListWidgetData[widgetName].queryOutput.records.push({values: values});
|
||||||
break;
|
break;
|
||||||
case "edit":
|
case "edit":
|
||||||
newChildListWidgetData[widgetName].queryOutput.records[rowIndex] = {values: values};
|
newChildListWidgetData[widgetName].queryOutput.records[rowIndex] = {values: values};
|
||||||
@ -255,7 +260,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
newChildListWidgetData[widgetName].totalRows = newChildListWidgetData[widgetName].queryOutput.records.length;
|
newChildListWidgetData[widgetName].totalRows = newChildListWidgetData[widgetName].queryOutput.records.length;
|
||||||
setChildListWidgetData(newChildListWidgetData);
|
setChildListWidgetData(newChildListWidgetData);
|
||||||
|
|
||||||
const newRenderedWidgetSections = Object.assign({}, renderedWidgetSections)
|
const newRenderedWidgetSections = Object.assign({}, renderedWidgetSections);
|
||||||
newRenderedWidgetSections[widgetName] = getWidgetSection(widgetMetaData, newChildListWidgetData[widgetName]);
|
newRenderedWidgetSections[widgetName] = getWidgetSection(widgetMetaData, newChildListWidgetData[widgetName]);
|
||||||
setRenderedWidgetSections(newRenderedWidgetSections);
|
setRenderedWidgetSections(newRenderedWidgetSections);
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
@ -293,11 +298,11 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
return <div>Error: No form fields in section {section.name}</div>;
|
return <div>Error: No form fields in section {section.name}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const helpRoles = [props.id ? "EDIT_SCREEN" : "INSERT_SCREEN", "WRITE_SCREENS", "ALL_SCREENS"]
|
const helpRoles = [props.id ? "EDIT_SCREEN" : "INSERT_SCREEN", "WRITE_SCREENS", "ALL_SCREENS"];
|
||||||
|
|
||||||
if(omitWrapper)
|
if (omitWrapper)
|
||||||
{
|
{
|
||||||
return <QDynamicForm formData={formData} record={record} helpRoles={helpRoles} helpContentKeyPrefix={`table:${tableName};`} />
|
return <QDynamicForm formData={formData} record={record} helpRoles={helpRoles} helpContentKeyPrefix={`table:${tableName};`} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Card id={section.name} sx={{overflow: "visible", scrollMarginTop: "100px"}} elevation={cardElevation}>
|
return <Card id={section.name} sx={{overflow: "visible", scrollMarginTop: "100px"}} elevation={cardElevation}>
|
||||||
@ -310,7 +315,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
<QDynamicForm formData={formData} record={record} helpRoles={helpRoles} helpContentKeyPrefix={`table:${tableName};`} />
|
<QDynamicForm formData={formData} record={record} helpRoles={helpRoles} helpContentKeyPrefix={`table:${tableName};`} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Card>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -332,7 +337,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
addNewRecordCallback={() => openAddChildRecord(widgetMetaData.name, widgetData)}
|
addNewRecordCallback={() => openAddChildRecord(widgetMetaData.name, widgetData)}
|
||||||
editRecordCallback={(rowIndex) => openEditChildRecord(widgetMetaData.name, widgetData, rowIndex)}
|
editRecordCallback={(rowIndex) => openEditChildRecord(widgetMetaData.name, widgetData, rowIndex)}
|
||||||
deleteRecordCallback={(rowIndex) => deleteChildRecord(widgetMetaData.name, widgetData, rowIndex)}
|
deleteRecordCallback={(rowIndex) => deleteChildRecord(widgetMetaData.name, widgetData, rowIndex)}
|
||||||
/>
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -341,13 +346,13 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
function renderSection(section: QTableSection, values: FormikValues | Value, touched: FormikTouched<FormikValues> | Value, formFields: Map<string, any>, errors: FormikErrors<FormikValues> | Value)
|
function renderSection(section: QTableSection, values: FormikValues | Value, touched: FormikTouched<FormikValues> | Value, formFields: Map<string, any>, errors: FormikErrors<FormikValues> | Value)
|
||||||
{
|
{
|
||||||
if(section.fieldNames && section.fieldNames.length > 0)
|
if (section.fieldNames && section.fieldNames.length > 0)
|
||||||
{
|
{
|
||||||
return getFormSection(section, values, touched, formFields.get(section.name), errors);
|
return getFormSection(section, values, touched, formFields.get(section.name), errors);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return renderedWidgetSections[section.widgetName] ?? <Box>Loading {section.label}...</Box>
|
return renderedWidgetSections[section.widgetName] ?? <Box>Loading {section.label}...</Box>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,7 +373,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
const tableSections = TableUtils.getSectionsForRecordSidebar(tableMetaData, [...tableMetaData.fields.keys()], (section: QTableSection) =>
|
const tableSections = TableUtils.getSectionsForRecordSidebar(tableMetaData, [...tableMetaData.fields.keys()], (section: QTableSection) =>
|
||||||
{
|
{
|
||||||
return section.widgetName && metaData.widgets.get(section.widgetName)?.type == "childRecordList" && metaData.widgets.get(section.widgetName)?.defaultValues?.has("manageAssociationName")
|
return section.widgetName && metaData.widgets.get(section.widgetName)?.type == "childRecordList" && metaData.widgets.get(section.widgetName)?.defaultValues?.has("manageAssociationName");
|
||||||
});
|
});
|
||||||
setTableSections(tableSections);
|
setTableSections(tableSections);
|
||||||
|
|
||||||
@ -410,7 +415,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// these checks are only for updating records, if copying, it is actually an insert, which is checked after this block //
|
// these checks are only for updating records, if copying, it is actually an insert, which is checked after this block //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if(! props.isCopy)
|
if (!props.isCopy)
|
||||||
{
|
{
|
||||||
if (!tableMetaData.capabilities.has(Capability.TABLE_UPDATE))
|
if (!tableMetaData.capabilities.has(Capability.TABLE_UPDATE))
|
||||||
{
|
{
|
||||||
@ -465,7 +470,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
// if an override heading was passed in, use it. //
|
// if an override heading was passed in, use it. //
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
if(props.overrideHeading)
|
if (props.overrideHeading)
|
||||||
{
|
{
|
||||||
setFormTitle(props.overrideHeading);
|
setFormTitle(props.overrideHeading);
|
||||||
if (!props.isModal)
|
if (!props.isModal)
|
||||||
@ -530,8 +535,8 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
let t1sectionName;
|
let t1sectionName;
|
||||||
let t1section;
|
let t1section;
|
||||||
const nonT1Sections: QTableSection[] = [];
|
const nonT1Sections: QTableSection[] = [];
|
||||||
const newRenderedWidgetSections: {[name: string]: JSX.Element} = {};
|
const newRenderedWidgetSections: { [name: string]: JSX.Element } = {};
|
||||||
const newChildListWidgetData: {[name: string]: ChildRecordListData} = {};
|
const newChildListWidgetData: { [name: string]: ChildRecordListData } = {};
|
||||||
|
|
||||||
for (let i = 0; i < tableSections.length; i++)
|
for (let i = 0; i < tableSections.length; i++)
|
||||||
{
|
{
|
||||||
@ -544,13 +549,13 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hasFields = section.fieldNames && section.fieldNames.length > 0;
|
const hasFields = section.fieldNames && section.fieldNames.length > 0;
|
||||||
const hasChildRecordListWidget = section.widgetName && metaData.widgets.get(section.widgetName)?.type == "childRecordList"
|
const hasChildRecordListWidget = section.widgetName && metaData.widgets.get(section.widgetName)?.type == "childRecordList";
|
||||||
if(!hasFields && !hasChildRecordListWidget)
|
if (!hasFields && !hasChildRecordListWidget)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hasFields)
|
if (hasFields)
|
||||||
{
|
{
|
||||||
for (let j = 0; j < section.fieldNames.length; j++)
|
for (let j = 0; j < section.fieldNames.length; j++)
|
||||||
{
|
{
|
||||||
@ -626,10 +631,10 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(childListWidgetData)
|
if (childListWidgetData)
|
||||||
{
|
{
|
||||||
const newRenderedWidgetSections: {[name: string]: JSX.Element} = {};
|
const newRenderedWidgetSections: { [name: string]: JSX.Element } = {};
|
||||||
for(let name in childListWidgetData)
|
for (let name in childListWidgetData)
|
||||||
{
|
{
|
||||||
const widgetMetaData = metaData.widgets.get(name);
|
const widgetMetaData = metaData.widgets.get(name);
|
||||||
newRenderedWidgetSections[name] = getWidgetSection(widgetMetaData, childListWidgetData[name]);
|
newRenderedWidgetSections[name] = getWidgetSection(widgetMetaData, childListWidgetData[name]);
|
||||||
@ -674,7 +679,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// if there's a callback (e.g., for a modal nested on another create/edit screen), then just pass our data back there anre return. //
|
// if there's a callback (e.g., for a modal nested on another create/edit screen), then just pass our data back there anre return. //
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if(props.onSubmitCallback)
|
if (props.onSubmitCallback)
|
||||||
{
|
{
|
||||||
props.onSubmitCallback(values);
|
props.onSubmitCallback(values);
|
||||||
return;
|
return;
|
||||||
@ -687,7 +692,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
const valuesToPost = JSON.parse(JSON.stringify(values));
|
const valuesToPost = JSON.parse(JSON.stringify(values));
|
||||||
|
|
||||||
for(let fieldName of tableMetaData.fields.keys())
|
for (let fieldName of tableMetaData.fields.keys())
|
||||||
{
|
{
|
||||||
const fieldMetaData = tableMetaData.fields.get(fieldName);
|
const fieldMetaData = tableMetaData.fields.get(fieldName);
|
||||||
|
|
||||||
@ -699,9 +704,9 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
// changing from, say, 12:15:30 to just 12:15:00... this seems to get around that, for cases when the //
|
// changing from, say, 12:15:30 to just 12:15:00... this seems to get around that, for cases when the //
|
||||||
// user didn't change the value in the field (but if the user did change the value, then we will submit it) //
|
// user didn't change the value in the field (but if the user did change the value, then we will submit it) //
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if(fieldMetaData.type === QFieldType.DATE_TIME && valuesToPost[fieldName])
|
if (fieldMetaData.type === QFieldType.DATE_TIME && valuesToPost[fieldName])
|
||||||
{
|
{
|
||||||
console.log(`DateTime ${fieldName}: Initial value: [${initialValues[fieldName]}] -> [${valuesToPost[fieldName]}]`)
|
console.log(`DateTime ${fieldName}: Initial value: [${initialValues[fieldName]}] -> [${valuesToPost[fieldName]}]`);
|
||||||
if (initialValues[fieldName] == valuesToPost[fieldName])
|
if (initialValues[fieldName] == valuesToPost[fieldName])
|
||||||
{
|
{
|
||||||
console.log(" - Is the same, so, deleting from the post");
|
console.log(" - Is the same, so, deleting from the post");
|
||||||
@ -720,12 +725,12 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
// 3) they are a String, which is their URL path to download them... in that case, don't submit them to //
|
// 3) they are a String, which is their URL path to download them... in that case, don't submit them to //
|
||||||
// the backend at all, so they'll stay what they were. do that by deleting them from the values object here. //
|
// the backend at all, so they'll stay what they were. do that by deleting them from the values object here. //
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if(fieldMetaData.type === QFieldType.BLOB)
|
if (fieldMetaData.type === QFieldType.BLOB)
|
||||||
{
|
{
|
||||||
if(typeof valuesToPost[fieldName] === "string")
|
if (typeof valuesToPost[fieldName] === "string")
|
||||||
{
|
{
|
||||||
console.log(`${fieldName} value was a string, so, we're deleting it from the values array, to not submit it to the backend, to not change it.`);
|
console.log(`${fieldName} value was a string, so, we're deleting it from the values array, to not submit it to the backend, to not change it.`);
|
||||||
delete(valuesToPost[fieldName]);
|
delete (valuesToPost[fieldName]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -734,23 +739,23 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const associationsToPost: any = {}
|
const associationsToPost: any = {};
|
||||||
let haveAssociationsToPost = false;
|
let haveAssociationsToPost = false;
|
||||||
for (let name of Object.keys(childListWidgetData))
|
for (let name of Object.keys(childListWidgetData))
|
||||||
{
|
{
|
||||||
const manageAssociationName = metaData.widgets.get(name)?.defaultValues?.get("manageAssociationName")
|
const manageAssociationName = metaData.widgets.get(name)?.defaultValues?.get("manageAssociationName");
|
||||||
if(!manageAssociationName)
|
if (!manageAssociationName)
|
||||||
{
|
{
|
||||||
console.log(`Cannot send association data to backend - missing a manageAssociationName defaultValue in widget meta data for widget name ${name}`);
|
console.log(`Cannot send association data to backend - missing a manageAssociationName defaultValue in widget meta data for widget name ${name}`);
|
||||||
}
|
}
|
||||||
associationsToPost[manageAssociationName] = [];
|
associationsToPost[manageAssociationName] = [];
|
||||||
haveAssociationsToPost = true;
|
haveAssociationsToPost = true;
|
||||||
for(let i=0; i<childListWidgetData[name].queryOutput?.records?.length; i++)
|
for (let i = 0; i < childListWidgetData[name].queryOutput?.records?.length; i++)
|
||||||
{
|
{
|
||||||
associationsToPost[manageAssociationName].push(childListWidgetData[name].queryOutput.records[i].values);
|
associationsToPost[manageAssociationName].push(childListWidgetData[name].queryOutput.records[i].values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(haveAssociationsToPost)
|
if (haveAssociationsToPost)
|
||||||
{
|
{
|
||||||
valuesToPost["associations"] = JSON.stringify(associationsToPost);
|
valuesToPost["associations"] = JSON.stringify(associationsToPost);
|
||||||
}
|
}
|
||||||
@ -771,7 +776,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
let warningMessage = null;
|
let warningMessage = null;
|
||||||
if(record.warnings && record.warnings.length && record.warnings.length > 0)
|
if (record.warnings && record.warnings.length && record.warnings.length > 0)
|
||||||
{
|
{
|
||||||
warningMessage = record.warnings[0];
|
warningMessage = record.warnings[0];
|
||||||
}
|
}
|
||||||
@ -785,7 +790,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
console.log("Caught:");
|
console.log("Caught:");
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
||||||
if(error.message.toLowerCase().startsWith("warning"))
|
if (error.message.toLowerCase().startsWith("warning"))
|
||||||
{
|
{
|
||||||
const path = location.pathname.replace(/\/edit$/, "");
|
const path = location.pathname.replace(/\/edit$/, "");
|
||||||
navigate(path, {state: {updateSuccess: true, warning: error.message}});
|
navigate(path, {state: {updateSuccess: true, warning: error.message}});
|
||||||
@ -814,7 +819,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
let warningMessage = null;
|
let warningMessage = null;
|
||||||
if(record.warnings && record.warnings.length && record.warnings.length > 0)
|
if (record.warnings && record.warnings.length && record.warnings.length > 0)
|
||||||
{
|
{
|
||||||
warningMessage = record.warnings[0];
|
warningMessage = record.warnings[0];
|
||||||
}
|
}
|
||||||
@ -827,7 +832,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
})
|
})
|
||||||
.catch((error) =>
|
.catch((error) =>
|
||||||
{
|
{
|
||||||
if(error.message.toLowerCase().startsWith("warning"))
|
if (error.message.toLowerCase().startsWith("warning"))
|
||||||
{
|
{
|
||||||
const path = props.isCopy ?
|
const path = props.isCopy ?
|
||||||
location.pathname.replace(new RegExp(`/${props.id}/copy$`), "/" + record.values.get(tableMetaData.primaryKeyField))
|
location.pathname.replace(new RegExp(`/${props.id}/copy$`), "/" + record.values.get(tableMetaData.primaryKeyField))
|
||||||
@ -850,15 +855,15 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
|
|
||||||
const getSectionHelp = (section: QTableSection) =>
|
const getSectionHelp = (section: QTableSection) =>
|
||||||
{
|
{
|
||||||
const helpRoles = [props.id ? "EDIT_SCREEN" : "INSERT_SCREEN", "WRITE_SCREENS", "ALL_SCREENS"]
|
const helpRoles = [props.id ? "EDIT_SCREEN" : "INSERT_SCREEN", "WRITE_SCREENS", "ALL_SCREENS"];
|
||||||
const formattedHelpContent = <HelpContent helpContents={section.helpContents} roles={helpRoles} helpContentKey={`table:${tableMetaData.name};section:${section.name}`} />;
|
const formattedHelpContent = <HelpContent helpContents={section.helpContents} roles={helpRoles} helpContentKey={`table:${tableMetaData.name};section:${section.name}`} />;
|
||||||
|
|
||||||
return formattedHelpContent && (
|
return formattedHelpContent && (
|
||||||
<Box px={"1.5rem"} fontSize={"0.875rem"}>
|
<Box px={"1.5rem"} fontSize={"0.875rem"}>
|
||||||
{formattedHelpContent}
|
{formattedHelpContent}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
if (notAllowedError)
|
if (notAllowedError)
|
||||||
{
|
{
|
||||||
@ -1007,7 +1012,7 @@ function EntityForm(props: Props): JSX.Element
|
|||||||
|
|
||||||
function ScrollToFirstError(): JSX.Element
|
function ScrollToFirstError(): JSX.Element
|
||||||
{
|
{
|
||||||
const {submitCount, isValid} = useFormikContext()
|
const {submitCount, isValid} = useFormikContext();
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@ -1037,8 +1042,8 @@ function ScrollToFirstError(): JSX.Element
|
|||||||
}
|
}
|
||||||
firstErrorMessage.scrollIntoView({block: "center"});
|
firstErrorMessage.scrollIntoView({block: "center"});
|
||||||
|
|
||||||
}, 100)
|
}, 100);
|
||||||
}, [submitCount, isValid])
|
}, [submitCount, isValid]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ function SavedViews({qController, metaData, tableMetaData, currentSavedView, tab
|
|||||||
const RENAME_OPTION = "Rename...";
|
const RENAME_OPTION = "Rename...";
|
||||||
const DELETE_OPTION = "Delete...";
|
const DELETE_OPTION = "Delete...";
|
||||||
const CLEAR_OPTION = "New View";
|
const CLEAR_OPTION = "New View";
|
||||||
const dropdownOptions = [DUPLICATE_OPTION, RENAME_OPTION, DELETE_OPTION, CLEAR_OPTION];
|
const NEW_REPORT_OPTION = "Create Report from Current View";
|
||||||
|
|
||||||
const {accentColor, accentColorLight} = useContext(QContext);
|
const {accentColor, accentColorLight} = useContext(QContext);
|
||||||
|
|
||||||
@ -187,10 +187,26 @@ function SavedViews({qController, metaData, tableMetaData, currentSavedView, tab
|
|||||||
case DELETE_OPTION:
|
case DELETE_OPTION:
|
||||||
setIsDeleteFilter(true)
|
setIsDeleteFilter(true)
|
||||||
break;
|
break;
|
||||||
|
case NEW_REPORT_OPTION:
|
||||||
|
createNewReport();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
function createNewReport()
|
||||||
|
{
|
||||||
|
const defaultValues: {[key: string]: any} = {};
|
||||||
|
defaultValues.tableName = tableMetaData.name;
|
||||||
|
defaultValues.queryFilterJson = JSON.stringify(view.queryFilter, null, 3);
|
||||||
|
defaultValues.columnsJson = JSON.stringify(view.queryColumns, null, 3);
|
||||||
|
navigate(`${metaData.getTablePathByName("savedReport")}/create#defaultValues=${encodeURIComponent(JSON.stringify(defaultValues))}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** fired when save or delete button saved on confirmation dialogs
|
** fired when save or delete button saved on confirmation dialogs
|
||||||
@ -376,6 +392,7 @@ function SavedViews({qController, metaData, tableMetaData, currentSavedView, tab
|
|||||||
const hasStorePermission = metaData?.processes.has("storeSavedView");
|
const hasStorePermission = metaData?.processes.has("storeSavedView");
|
||||||
const hasDeletePermission = metaData?.processes.has("deleteSavedView");
|
const hasDeletePermission = metaData?.processes.has("deleteSavedView");
|
||||||
const hasQueryPermission = metaData?.processes.has("querySavedView");
|
const hasQueryPermission = metaData?.processes.has("querySavedView");
|
||||||
|
const hasSavedReportsPermission = metaData?.tables.has("savedReport");
|
||||||
|
|
||||||
const tooltipMaxWidth = (maxWidth: string) =>
|
const tooltipMaxWidth = (maxWidth: string) =>
|
||||||
{
|
{
|
||||||
@ -429,7 +446,7 @@ function SavedViews({qController, metaData, tableMetaData, currentSavedView, tab
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
hasStorePermission && currentSavedView != null &&
|
hasDeletePermission && currentSavedView != null &&
|
||||||
<Tooltip {...menuTooltipAttribs} title="Delete this saved view.">
|
<Tooltip {...menuTooltipAttribs} title="Delete this saved view.">
|
||||||
<MenuItem disabled={currentSavedView === null} onClick={() => handleDropdownOptionClick(DELETE_OPTION)}>
|
<MenuItem disabled={currentSavedView === null} onClick={() => handleDropdownOptionClick(DELETE_OPTION)}>
|
||||||
<ListItemIcon><Icon>delete</Icon></ListItemIcon>
|
<ListItemIcon><Icon>delete</Icon></ListItemIcon>
|
||||||
@ -445,6 +462,15 @@ function SavedViews({qController, metaData, tableMetaData, currentSavedView, tab
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
hasSavedReportsPermission &&
|
||||||
|
<Tooltip {...menuTooltipAttribs} title="Create a new Saved Report using your current view of this table as a starting point.">
|
||||||
|
<MenuItem onClick={() => handleDropdownOptionClick(NEW_REPORT_OPTION)}>
|
||||||
|
<ListItemIcon><Icon>article</Icon></ListItemIcon>
|
||||||
|
Create Report from Current View
|
||||||
|
</MenuItem>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
<Divider/>
|
<Divider/>
|
||||||
<MenuItem disabled style={{"opacity": "initial"}}><b>Your Saved Views</b></MenuItem>
|
<MenuItem disabled style={{"opacity": "initial"}}><b>Your Saved Views</b></MenuItem>
|
||||||
{
|
{
|
||||||
|
@ -47,9 +47,6 @@ import {DataGridPro, GridColDef} from "@mui/x-data-grid-pro";
|
|||||||
import FormData from "form-data";
|
import FormData from "form-data";
|
||||||
import {Form, Formik} from "formik";
|
import {Form, Formik} from "formik";
|
||||||
import parse from "html-react-parser";
|
import parse from "html-react-parser";
|
||||||
import React, {useContext, useEffect, useState} from "react";
|
|
||||||
import {useLocation, useNavigate, useParams} from "react-router-dom";
|
|
||||||
import * as Yup from "yup";
|
|
||||||
import QContext from "QContext";
|
import QContext from "QContext";
|
||||||
import {QCancelButton, QSubmitButton} from "qqq/components/buttons/DefaultButtons";
|
import {QCancelButton, QSubmitButton} from "qqq/components/buttons/DefaultButtons";
|
||||||
import QDynamicForm from "qqq/components/forms/DynamicForm";
|
import QDynamicForm from "qqq/components/forms/DynamicForm";
|
||||||
@ -66,6 +63,9 @@ import {TABLE_VARIANT_LOCAL_STORAGE_KEY_ROOT} from "qqq/pages/records/query/Reco
|
|||||||
import Client from "qqq/utils/qqq/Client";
|
import Client from "qqq/utils/qqq/Client";
|
||||||
import TableUtils from "qqq/utils/qqq/TableUtils";
|
import TableUtils from "qqq/utils/qqq/TableUtils";
|
||||||
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
||||||
|
import React, {useContext, useEffect, useState} from "react";
|
||||||
|
import {useLocation, useNavigate, useParams} from "react-router-dom";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
@ -226,8 +226,19 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
setShowFullHelpText(!showFullHelpText);
|
setShowFullHelpText(!showFullHelpText);
|
||||||
};
|
};
|
||||||
|
|
||||||
const download = (url: string, fileName: string) =>
|
const download = (processValues: {[key: string]: string}) =>
|
||||||
{
|
{
|
||||||
|
let url;
|
||||||
|
let fileName = processValues.downloadFileName;
|
||||||
|
if(processValues.serverFilePath)
|
||||||
|
{
|
||||||
|
url = `/download/${encodeURIComponent(processValues.downloadFileName)}?filePath=${encodeURIComponent(processValues.serverFilePath)}`;
|
||||||
|
}
|
||||||
|
else if(processValues.storageTableName && processValues.storageReference)
|
||||||
|
{
|
||||||
|
url = `/download/${encodeURIComponent(processValues.downloadFileName)}?storageTableName=${encodeURIComponent(processValues.storageTableName)}&storageReference=${encodeURIComponent(processValues.storageReference)}`;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// todo - this could be simplified, i think? //
|
// todo - this could be simplified, i think? //
|
||||||
// it was originally built like this when we had to submit full access token to backend... //
|
// it was originally built like this when we had to submit full access token to backend... //
|
||||||
@ -556,7 +567,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
|||||||
Download
|
Download
|
||||||
</Box>
|
</Box>
|
||||||
<Box display="flex" py={1} pr={2}>
|
<Box display="flex" py={1} pr={2}>
|
||||||
<MDTypography variant="button" fontWeight="bold" onClick={() => download(`/download/${processValues.downloadFileName}?filePath=${processValues.serverFilePath}`, processValues.downloadFileName)} sx={{cursor: "pointer"}}>
|
<MDTypography variant="button" fontWeight="bold" onClick={() => download(processValues)} sx={{cursor: "pointer"}}>
|
||||||
<Box display="flex" alignItems="center" gap={1} py={1} pr={2}>
|
<Box display="flex" alignItems="center" gap={1} py={1} pr={2}>
|
||||||
<Icon fontSize="large">download_for_offline</Icon>
|
<Icon fontSize="large">download_for_offline</Icon>
|
||||||
{processValues.downloadFileName}
|
{processValues.downloadFileName}
|
||||||
|
Reference in New Issue
Block a user