mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 05:10:45 +00:00
Update to support opening child editing form via url (hash or sub-path); also proceses on record-view via hash
This commit is contained in:
14
src/App.tsx
14
src/App.tsx
@ -278,6 +278,16 @@ export default function App()
|
|||||||
component: <EntityCreate table={table} />,
|
component: <EntityCreate table={table} />,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// this is the path to open a modal-form when viewing a record, to create a different (child) record //
|
||||||
|
// it can also be done with a hash like: #/createChild=:childTableName //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
routeList.push({
|
||||||
|
key: `${app.name}.createChild`,
|
||||||
|
route: `${path}/:id/createChild/:childTableName`,
|
||||||
|
component: <EntityView table={table} />,
|
||||||
|
});
|
||||||
|
|
||||||
routeList.push({
|
routeList.push({
|
||||||
name: `${app.label} View`,
|
name: `${app.label} View`,
|
||||||
key: `${app.name}.view`,
|
key: `${app.name}.view`,
|
||||||
@ -302,6 +312,10 @@ export default function App()
|
|||||||
const processesForTable = QProcessUtils.getProcessesForTable(metaData, table.name, true);
|
const processesForTable = QProcessUtils.getProcessesForTable(metaData, table.name, true);
|
||||||
processesForTable.forEach((process) =>
|
processesForTable.forEach((process) =>
|
||||||
{
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// paths to open modal process under its owning table. //
|
||||||
|
// note, processes can also be launched (at least initially on entityView screen) with a hash like: #/launchProcess=:processName //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
routeList.push({
|
routeList.push({
|
||||||
name: process.label,
|
name: process.label,
|
||||||
key: process.name,
|
key: process.name,
|
||||||
|
@ -34,7 +34,7 @@ import Grid from "@mui/material/Grid";
|
|||||||
import Icon from "@mui/material/Icon";
|
import Icon from "@mui/material/Icon";
|
||||||
import {Form, Formik} from "formik";
|
import {Form, Formik} from "formik";
|
||||||
import React, {useContext, useReducer, useState} from "react";
|
import React, {useContext, useReducer, useState} from "react";
|
||||||
import {useLocation, useNavigate, useParams} from "react-router-dom";
|
import {useLocation, useNavigate, useParams, useSearchParams} from "react-router-dom";
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
import QContext from "QContext";
|
import QContext from "QContext";
|
||||||
import {QCancelButton, QSaveButton} from "qqq/components/QButtons";
|
import {QCancelButton, QSaveButton} from "qqq/components/QButtons";
|
||||||
@ -67,11 +67,11 @@ EntityForm.defaultProps = {
|
|||||||
disabledFields: {},
|
disabledFields: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disabledFields}: Props): JSX.Element
|
function EntityForm(props: Props): JSX.Element
|
||||||
{
|
{
|
||||||
const qController = QClient.getInstance();
|
const qController = QClient.getInstance();
|
||||||
const tableNameParam = useParams().tableName;
|
const tableNameParam = useParams().tableName;
|
||||||
const tableName = table === null ? tableNameParam : table.name;
|
const tableName = props.table === null ? tableNameParam : props.table.name;
|
||||||
|
|
||||||
const [formTitle, setFormTitle] = useState("");
|
const [formTitle, setFormTitle] = useState("");
|
||||||
const [validations, setValidations] = useState({});
|
const [validations, setValidations] = useState({});
|
||||||
@ -96,6 +96,34 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// first take defaultValues and disabledFields from props //
|
||||||
|
// but, also allow them to be sent in the hash, in the format of: //
|
||||||
|
// #/defaultValues={jsonName=value}/disabledFields={jsonName=any} //
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
let defaultValues = props.defaultValues;
|
||||||
|
let disabledFields = props.disabledFields;
|
||||||
|
|
||||||
|
const hashParts = location.hash.split("/");
|
||||||
|
for (let i = 0; i < hashParts.length; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const parts = hashParts[i].split("=")
|
||||||
|
if (parts.length > 1 && parts[0] == "defaultValues")
|
||||||
|
{
|
||||||
|
defaultValues = JSON.parse(decodeURIComponent(parts[1])) as { [key: string]: any };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.length > 1 && parts[0] == "disabledFields")
|
||||||
|
{
|
||||||
|
disabledFields = JSON.parse(decodeURIComponent(parts[1])) as { [key: string]: any };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
function getFormSection(values: any, touched: any, formFields: any, errors: any): JSX.Element
|
function getFormSection(values: any, touched: any, formFields: any, errors: any): JSX.Element
|
||||||
{
|
{
|
||||||
const formData: any = {};
|
const formData: any = {};
|
||||||
@ -142,13 +170,13 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
let record: QRecord = null;
|
let record: QRecord = null;
|
||||||
let defaultDisplayValues = new Map<string, string>();
|
let defaultDisplayValues = new Map<string, string>();
|
||||||
if (id !== null)
|
if (props.id !== null)
|
||||||
{
|
{
|
||||||
record = await qController.get(tableName, id);
|
record = await qController.get(tableName, props.id);
|
||||||
setRecord(record);
|
setRecord(record);
|
||||||
setFormTitle(`Edit ${tableMetaData?.label}: ${record?.recordLabel}`);
|
setFormTitle(`Edit ${tableMetaData?.label}: ${record?.recordLabel}`);
|
||||||
|
|
||||||
if (!isModal)
|
if (!props.isModal)
|
||||||
{
|
{
|
||||||
setPageHeader(`Edit ${tableMetaData?.label}: ${record?.recordLabel}`);
|
setPageHeader(`Edit ${tableMetaData?.label}: ${record?.recordLabel}`);
|
||||||
}
|
}
|
||||||
@ -172,7 +200,7 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
setFormTitle(`Creating New ${tableMetaData?.label}`);
|
setFormTitle(`Creating New ${tableMetaData?.label}`);
|
||||||
|
|
||||||
if (!isModal)
|
if (!props.isModal)
|
||||||
{
|
{
|
||||||
setPageHeader(`Creating New ${tableMetaData?.label}`);
|
setPageHeader(`Creating New ${tableMetaData?.label}`);
|
||||||
}
|
}
|
||||||
@ -268,7 +296,7 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
// if id !== null - means we're on the edit screen -- show all fields on the edit screen. //
|
// if id !== null - means we're on the edit screen -- show all fields on the edit screen. //
|
||||||
// || (or) we're on the insert screen in which case, only show editable fields. //
|
// || (or) we're on the insert screen in which case, only show editable fields. //
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if (id !== null || field.isEditable)
|
if (props.id !== null || field.isEditable)
|
||||||
{
|
{
|
||||||
sectionDynamicFormFields.push(dynamicFormFields[fieldName]);
|
sectionDynamicFormFields.push(dynamicFormFields[fieldName]);
|
||||||
}
|
}
|
||||||
@ -316,7 +344,7 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
// but if the user used the anchors on the page, this doesn't effectively cancel... //
|
// but if the user used the anchors on the page, this doesn't effectively cancel... //
|
||||||
// what we have here pushed a new history entry (I think?), so could be better //
|
// what we have here pushed a new history entry (I think?), so could be better //
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
if (id !== null)
|
if (props.id !== null)
|
||||||
{
|
{
|
||||||
const path = `${location.pathname.replace(/\/edit$/, "")}`;
|
const path = `${location.pathname.replace(/\/edit$/, "")}`;
|
||||||
navigate(path, {replace: true});
|
navigate(path, {replace: true});
|
||||||
@ -333,15 +361,15 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
actions.setSubmitting(true);
|
actions.setSubmitting(true);
|
||||||
await (async () =>
|
await (async () =>
|
||||||
{
|
{
|
||||||
if (id !== null)
|
if (props.id !== null)
|
||||||
{
|
{
|
||||||
await qController
|
await qController
|
||||||
.update(tableName, id, values)
|
.update(tableName, props.id, values)
|
||||||
.then((record) =>
|
.then((record) =>
|
||||||
{
|
{
|
||||||
if (isModal)
|
if (props.isModal)
|
||||||
{
|
{
|
||||||
closeModalHandler(null, "recordUpdated");
|
props.closeModalHandler(null, "recordUpdated");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -362,9 +390,9 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
.create(tableName, values)
|
.create(tableName, values)
|
||||||
.then((record) =>
|
.then((record) =>
|
||||||
{
|
{
|
||||||
if (isModal)
|
if (props.isModal)
|
||||||
{
|
{
|
||||||
closeModalHandler(null, "recordCreated");
|
props.closeModalHandler(null, "recordCreated");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -380,7 +408,7 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
})();
|
})();
|
||||||
};
|
};
|
||||||
|
|
||||||
const formId = id != null ? `edit-${tableMetaData?.name}-form` : `create-${tableMetaData?.name}-form`;
|
const formId = props.id != null ? `edit-${tableMetaData?.name}-form` : `create-${tableMetaData?.name}-form`;
|
||||||
|
|
||||||
let body;
|
let body;
|
||||||
if (noCapabilityError)
|
if (noCapabilityError)
|
||||||
@ -399,7 +427,7 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const cardElevation = isModal ? 3 : 1;
|
const cardElevation = props.isModal ? 3 : 1;
|
||||||
body = (
|
body = (
|
||||||
<MDBox mb={3}>
|
<MDBox mb={3}>
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
@ -413,12 +441,12 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
{
|
{
|
||||||
!isModal &&
|
!props.isModal &&
|
||||||
<Grid item xs={12} lg={3}>
|
<Grid item xs={12} lg={3}>
|
||||||
<QRecordSidebar tableSections={tableSections} />
|
<QRecordSidebar tableSections={tableSections} />
|
||||||
</Grid>
|
</Grid>
|
||||||
}
|
}
|
||||||
<Grid item xs={12} lg={isModal ? 12 : 9}>
|
<Grid item xs={12} lg={props.isModal ? 12 : 9}>
|
||||||
|
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
@ -475,7 +503,7 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
|
|
||||||
<MDBox component="div" p={3}>
|
<MDBox component="div" p={3}>
|
||||||
<Grid container justifyContent="flex-end" spacing={3}>
|
<Grid container justifyContent="flex-end" spacing={3}>
|
||||||
<QCancelButton onClickHandler={isModal ? closeModalHandler : handleCancelClicked} disabled={isSubmitting} />
|
<QCancelButton onClickHandler={props.isModal ? props.closeModalHandler : handleCancelClicked} disabled={isSubmitting} />
|
||||||
<QSaveButton disabled={isSubmitting} />
|
<QSaveButton disabled={isSubmitting} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</MDBox>
|
</MDBox>
|
||||||
@ -490,7 +518,7 @@ function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disab
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isModal)
|
if (props.isModal)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Box sx={{position: "absolute", overflowY: "auto", maxHeight: "100%", width: "100%"}}>
|
<Box sx={{position: "absolute", overflowY: "auto", maxHeight: "100%", width: "100%"}}>
|
||||||
|
@ -24,7 +24,7 @@ import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
|||||||
import {DataGridPro} from "@mui/x-data-grid-pro";
|
import {DataGridPro} from "@mui/x-data-grid-pro";
|
||||||
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 Widget, {AddNewRecordButton, HeaderLink} from "./Widget";
|
import Widget, {AddNewRecordButton, HeaderLink, LabelComponent} from "./Widget";
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
{
|
{
|
||||||
@ -65,15 +65,23 @@ function RecordGridWidget({title, data, reloadWidgetCallback}: Props): JSX.Eleme
|
|||||||
}
|
}
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
|
const labelAdditionalComponentsLeft: LabelComponent[] = []
|
||||||
|
if(data && data.viewAllLink)
|
||||||
|
{
|
||||||
|
labelAdditionalComponentsLeft.push(new HeaderLink("View All", data.viewAllLink));
|
||||||
|
}
|
||||||
|
|
||||||
|
const labelAdditionalComponentsRight: LabelComponent[] = []
|
||||||
|
if(data && data.canAddChildRecord)
|
||||||
|
{
|
||||||
|
labelAdditionalComponentsRight.push(new AddNewRecordButton(data.childTableMetaData, data.defaultValuesForNewChildRecords))
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Widget
|
<Widget
|
||||||
label={title}
|
label={title}
|
||||||
labelAdditionalComponentsLeft={[
|
labelAdditionalComponentsLeft={labelAdditionalComponentsLeft}
|
||||||
new HeaderLink("View All", data.viewAllLink)
|
labelAdditionalComponentsRight={labelAdditionalComponentsRight}
|
||||||
]}
|
|
||||||
labelAdditionalComponentsRight={[
|
|
||||||
new AddNewRecordButton(data.childTableMetaData, data.defaultValuesForNewChildRecords)
|
|
||||||
]}
|
|
||||||
reloadWidgetCallback={reloadWidgetCallback}
|
reloadWidgetCallback={reloadWidgetCallback}
|
||||||
>
|
>
|
||||||
<DataGridPro
|
<DataGridPro
|
||||||
|
@ -26,14 +26,14 @@ import Card from "@mui/material/Card";
|
|||||||
import Modal from "@mui/material/Modal";
|
import Modal from "@mui/material/Modal";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {Link} from "react-router-dom";
|
import {Link, useNavigate} from "react-router-dom";
|
||||||
import EntityForm from "qqq/components/EntityForm";
|
import EntityForm from "qqq/components/EntityForm";
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
{
|
{
|
||||||
label: string;
|
label: string;
|
||||||
labelAdditionalComponentsLeft: [LabelComponent];
|
labelAdditionalComponentsLeft: LabelComponent[];
|
||||||
labelAdditionalComponentsRight: [LabelComponent];
|
labelAdditionalComponentsRight: LabelComponent[];
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
reloadWidgetCallback?: (widgetIndex: number, params: string) => void;
|
reloadWidgetCallback?: (widgetIndex: number, params: string) => void;
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ Widget.defaultProps = {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LabelComponent
|
export class LabelComponent
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -89,40 +89,13 @@ export class AddNewRecordButton extends LabelComponent
|
|||||||
|
|
||||||
function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
||||||
{
|
{
|
||||||
const [showEditForm, setShowEditForm] = useState(null as any);
|
const navigate = useNavigate();
|
||||||
|
|
||||||
function openEditForm(table: QTableMetaData, id: any = null, defaultValues: any, disabledFields: any)
|
function openEditForm(table: QTableMetaData, id: any = null, defaultValues: any, disabledFields: any)
|
||||||
{
|
{
|
||||||
const showEditForm: any = {};
|
navigate(`#/createChild=${table.name}/defaultValues=${JSON.stringify(defaultValues)}/disabledFields=${JSON.stringify(disabledFields)}`)
|
||||||
showEditForm.table = table;
|
|
||||||
showEditForm.id = id;
|
|
||||||
showEditForm.defaultValues = defaultValues;
|
|
||||||
showEditForm.disabledFields = disabledFields;
|
|
||||||
setShowEditForm(showEditForm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeEditForm = (event: object, reason: string) =>
|
|
||||||
{
|
|
||||||
if (reason === "backdropClick")
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reason === "recordUpdated" || reason === "recordCreated")
|
|
||||||
{
|
|
||||||
if(props.reloadWidgetCallback)
|
|
||||||
{
|
|
||||||
props.reloadWidgetCallback(0, "ok");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
window.location.reload()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setShowEditForm(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
function renderComponent(component: LabelComponent)
|
function renderComponent(component: LabelComponent)
|
||||||
{
|
{
|
||||||
if(component instanceof HeaderLink)
|
if(component instanceof HeaderLink)
|
||||||
@ -152,7 +125,7 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
|||||||
<Card sx={{width: "100%"}}>
|
<Card sx={{width: "100%"}}>
|
||||||
<Box display="flex" justifyContent="space-between" alignItems="center">
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
<Box py={2}>
|
<Box py={2}>
|
||||||
<Typography variant="h6" fontWeight="medium" p={3} display="inline">
|
<Typography variant="h5" fontWeight="medium" p={3} display="inline">
|
||||||
{props.label}
|
{props.label}
|
||||||
</Typography>
|
</Typography>
|
||||||
{
|
{
|
||||||
@ -173,20 +146,6 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
|
|||||||
</Box>
|
</Box>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Card>
|
</Card>
|
||||||
{
|
|
||||||
showEditForm &&
|
|
||||||
<Modal open={showEditForm as boolean} onClose={(event, reason) => closeEditForm(event, reason)}>
|
|
||||||
<div className="modalEditForm">
|
|
||||||
<EntityForm
|
|
||||||
isModal={true}
|
|
||||||
closeModalHandler={closeEditForm}
|
|
||||||
table={showEditForm.table}
|
|
||||||
id={showEditForm.id}
|
|
||||||
defaultValues={showEditForm.defaultValues}
|
|
||||||
disabledFields={showEditForm.disabledFields} />
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -795,7 +795,7 @@ function EntityList({table, launchProcess}: Props): JSX.Element
|
|||||||
|
|
||||||
const closeModalProcess = (event: object, reason: string) =>
|
const closeModalProcess = (event: object, reason: string) =>
|
||||||
{
|
{
|
||||||
if (reason === "backdropClick")
|
if (reason === "backdropClick" || reason === "escapeKeyDown")
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ function EntityDeveloperView({table}: Props): JSX.Element
|
|||||||
|
|
||||||
const closeEditingScript = (event: object, reason: string, alert: string = null) =>
|
const closeEditingScript = (event: object, reason: string, alert: string = null) =>
|
||||||
{
|
{
|
||||||
if (reason === "backdropClick")
|
if (reason === "backdropClick" || reason === "escapeKeyDown")
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import {useLocation, useNavigate, useParams, useSearchParams} from "react-router
|
|||||||
import QContext from "QContext";
|
import QContext from "QContext";
|
||||||
import BaseLayout from "qqq/components/BaseLayout";
|
import BaseLayout from "qqq/components/BaseLayout";
|
||||||
import DashboardWidgets from "qqq/components/DashboardWidgets";
|
import DashboardWidgets from "qqq/components/DashboardWidgets";
|
||||||
|
import EntityForm from "qqq/components/EntityForm";
|
||||||
import {QActionsMenuButton, QDeleteButton, QEditButton} from "qqq/components/QButtons";
|
import {QActionsMenuButton, QDeleteButton, QEditButton} from "qqq/components/QButtons";
|
||||||
import QRecordSidebar from "qqq/components/QRecordSidebar";
|
import QRecordSidebar from "qqq/components/QRecordSidebar";
|
||||||
import colors from "qqq/components/Temporary/colors";
|
import colors from "qqq/components/Temporary/colors";
|
||||||
@ -60,7 +61,6 @@ import QValueUtils from "qqq/utils/QValueUtils";
|
|||||||
|
|
||||||
const qController = QClient.getInstance();
|
const qController = QClient.getInstance();
|
||||||
|
|
||||||
// Declaring props types for ViewForm
|
|
||||||
interface Props
|
interface Props
|
||||||
{
|
{
|
||||||
table?: QTableMetaData;
|
table?: QTableMetaData;
|
||||||
@ -70,7 +70,7 @@ interface Props
|
|||||||
EntityView.defaultProps =
|
EntityView.defaultProps =
|
||||||
{
|
{
|
||||||
table: null,
|
table: null,
|
||||||
launchProcess: null
|
launchProcess: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
function EntityView({table, launchProcess}: Props): JSX.Element
|
function EntityView({table, launchProcess}: Props): JSX.Element
|
||||||
@ -102,6 +102,7 @@ function EntityView({table, launchProcess}: Props): JSX.Element
|
|||||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||||
|
|
||||||
const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
|
const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
|
||||||
|
const [showEditChildForm, setShowEditChildForm] = useState(null as any);
|
||||||
|
|
||||||
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
|
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
|
||||||
const closeActionsMenu = () => setActionsMenu(null);
|
const closeActionsMenu = () => setActionsMenu(null);
|
||||||
@ -126,10 +127,16 @@ function EntityView({table, launchProcess}: Props): JSX.Element
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
/////////////////////////////////////////////////////////////////
|
const hashParts = location.hash.split("/");
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// the path for a process looks like: .../table/id/process //
|
// the path for a process looks like: .../table/id/process //
|
||||||
// so if our tableName is in the -3 index, try to open process //
|
// the path for creating a child record looks like: .../table/id/createChild/:childTableName //
|
||||||
/////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
// if our tableName is in the -3 index, try to open process //
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
if (pathParts[pathParts.length - 3] === tableName)
|
if (pathParts[pathParts.length - 3] === tableName)
|
||||||
{
|
{
|
||||||
const processName = pathParts[pathParts.length - 1];
|
const processName = pathParts[pathParts.length - 1];
|
||||||
@ -144,19 +151,69 @@ function EntityView({table, launchProcess}: Props): JSX.Element
|
|||||||
console.log(`Couldn't find process named ${processName}`);
|
console.log(`Couldn't find process named ${processName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// alternatively, look for a launchProcess specification in the hash //
|
||||||
|
// e.g., for non-natively rendered links to open the modal. //
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
for (let i = 0; i < hashParts.length; i++)
|
||||||
|
{
|
||||||
|
const parts = hashParts[i].split("=")
|
||||||
|
if (parts.length > 1 && parts[0] == "launchProcess")
|
||||||
|
{
|
||||||
|
(async () =>
|
||||||
|
{
|
||||||
|
const processMetaData = await qController.loadProcessMetaData(parts[1])
|
||||||
|
setActiveModalProcess(processMetaData);
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if our table is in the -4 index, and there's `createChild` in the -2 index, try to open a createChild form //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if(pathParts[pathParts.length - 4] === tableName && pathParts[pathParts.length - 2] == "createChild")
|
||||||
|
{
|
||||||
|
(async () =>
|
||||||
|
{
|
||||||
|
const childTable = await qController.loadTableMetaData(pathParts[pathParts.length - 1])
|
||||||
|
const childId: any = null; // todo - for editing a child, not just creating one.
|
||||||
|
openEditChildForm(childTable, childId, null, null); // todo - defaults & disableds
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// alternatively, look for a createChild specification in the hash //
|
||||||
|
// e.g., for non-natively rendered links to open the modal. //
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
for (let i = 0; i < hashParts.length; i++)
|
||||||
|
{
|
||||||
|
const parts = hashParts[i].split("=")
|
||||||
|
if (parts.length > 1 && parts[0] == "createChild")
|
||||||
|
{
|
||||||
|
(async () =>
|
||||||
|
{
|
||||||
|
const childTable = await qController.loadTableMetaData(parts[1])
|
||||||
|
const childId: any = null; // todo - for editing a child, not just creating one.
|
||||||
|
openEditChildForm(childTable, childId, null, null); // todo - defaults & disableds
|
||||||
|
})();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
// if we didn't open a process, assume we need to (re)load //
|
// if we didn't open something, then, assume we need to (re)load //
|
||||||
/////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
reload();
|
|
||||||
|
|
||||||
setActiveModalProcess(null);
|
setActiveModalProcess(null);
|
||||||
}, [location.pathname]);
|
reload();
|
||||||
|
}, [location.pathname, location.hash]);
|
||||||
|
|
||||||
if (!asyncLoadInited)
|
if (!asyncLoadInited)
|
||||||
{
|
{
|
||||||
@ -275,7 +332,7 @@ function EntityView({table, launchProcess}: Props): JSX.Element
|
|||||||
<Grid id={section.name} key={section.name} item lg={12} xs={12} sx={{display: "flex", alignItems: "stretch", scrollMarginTop: "100px"}}>
|
<Grid id={section.name} key={section.name} item lg={12} xs={12} sx={{display: "flex", alignItems: "stretch", scrollMarginTop: "100px"}}>
|
||||||
<MDBox width="100%">
|
<MDBox width="100%">
|
||||||
<Card id={section.name} sx={{overflow: "visible", scrollMarginTop: "100px"}}>
|
<Card id={section.name} sx={{overflow: "visible", scrollMarginTop: "100px"}}>
|
||||||
<MDTypography variant="h6" p={3} pb={1}>
|
<MDTypography variant="h5" p={3} pb={1}>
|
||||||
{section.label}
|
{section.label}
|
||||||
</MDTypography>
|
</MDTypography>
|
||||||
<MDBox p={3} pt={0} flexDirection="column">
|
<MDBox p={3} pt={0} flexDirection="column">
|
||||||
@ -395,7 +452,7 @@ function EntityView({table, launchProcess}: Props): JSX.Element
|
|||||||
|
|
||||||
const closeModalProcess = (event: object, reason: string) =>
|
const closeModalProcess = (event: object, reason: string) =>
|
||||||
{
|
{
|
||||||
if (reason === "backdropClick")
|
if (reason === "backdropClick" || reason === "escapeKeyDown")
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -403,9 +460,53 @@ function EntityView({table, launchProcess}: Props): JSX.Element
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// when closing a modal process, navigate up to the record being viewed //
|
// when closing a modal process, navigate up to the record being viewed //
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
if(location.hash)
|
||||||
|
{
|
||||||
|
navigate(location.pathname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
const newPath = location.pathname.split("/");
|
const newPath = location.pathname.split("/");
|
||||||
newPath.pop();
|
newPath.pop();
|
||||||
navigate(newPath.join("/"));
|
navigate(newPath.join("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
setActiveModalProcess(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
function openEditChildForm(table: QTableMetaData, id: any = null, defaultValues: any, disabledFields: any)
|
||||||
|
{
|
||||||
|
const showEditChildForm: any = {};
|
||||||
|
showEditChildForm.table = table;
|
||||||
|
showEditChildForm.id = id;
|
||||||
|
showEditChildForm.defaultValues = defaultValues;
|
||||||
|
showEditChildForm.disabledFields = disabledFields;
|
||||||
|
setShowEditChildForm(showEditChildForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeEditChildForm = (event: object, reason: string) =>
|
||||||
|
{
|
||||||
|
if (reason === "backdropClick" || reason === "escapeKeyDown")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// navigate back up to the record being viewed //
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
if(location.hash)
|
||||||
|
{
|
||||||
|
navigate(location.pathname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const newPath = location.pathname.split("/");
|
||||||
|
newPath.pop();
|
||||||
|
newPath.pop();
|
||||||
|
navigate(newPath.join("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
setShowEditChildForm(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -515,6 +616,21 @@ function EntityView({table, launchProcess}: Props): JSX.Element
|
|||||||
</Modal>
|
</Modal>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
showEditChildForm &&
|
||||||
|
<Modal open={showEditChildForm as boolean} onClose={(event, reason) => closeEditChildForm(event, reason)}>
|
||||||
|
<div className="modalEditForm">
|
||||||
|
<EntityForm
|
||||||
|
isModal={true}
|
||||||
|
closeModalHandler={closeEditChildForm}
|
||||||
|
table={showEditChildForm.table}
|
||||||
|
id={showEditChildForm.id}
|
||||||
|
defaultValues={showEditChildForm.defaultValues}
|
||||||
|
disabledFields={showEditChildForm.disabledFields} />
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
}
|
||||||
|
|
||||||
</MDBox>
|
</MDBox>
|
||||||
}
|
}
|
||||||
</MDBox>
|
</MDBox>
|
||||||
|
Reference in New Issue
Block a user