mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-17 21:00:45 +00:00
Switch to use modal processes
This commit is contained in:
10
src/App.tsx
10
src/App.tsx
@ -269,13 +269,21 @@ export default function App()
|
|||||||
name: process.label,
|
name: process.label,
|
||||||
key: process.name,
|
key: process.name,
|
||||||
route: `${path}/${process.name}`,
|
route: `${path}/${process.name}`,
|
||||||
component: <ProcessRun process={process} />,
|
component: <EntityList table={table} launchProcess={process} />,
|
||||||
|
});
|
||||||
|
|
||||||
|
routeList.push({
|
||||||
|
name: process.label,
|
||||||
|
key: `${app.name}/${process.name}`,
|
||||||
|
route: `${path}/:id/${process.name}`,
|
||||||
|
component: <EntityView table={table} launchProcess={process} />,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const reportsForTable = QProcessUtils.getReportsForTable(metaData, table.name, true);
|
const reportsForTable = QProcessUtils.getReportsForTable(metaData, table.name, true);
|
||||||
reportsForTable.forEach((report) =>
|
reportsForTable.forEach((report) =>
|
||||||
{
|
{
|
||||||
|
// todo - do we need some table/report routes here, that would go to EntityList and/or EntityView
|
||||||
routeList.push({
|
routeList.push({
|
||||||
name: report.label,
|
name: report.label,
|
||||||
key: report.name,
|
key: report.name,
|
||||||
|
@ -102,8 +102,8 @@ function DashboardWidgets({widgetMetaDataList, entityPrimaryKey}: Props): JSX.El
|
|||||||
};
|
};
|
||||||
|
|
||||||
const widgetCount = widgetMetaDataList ? widgetMetaDataList.length : 0;
|
const widgetCount = widgetMetaDataList ? widgetMetaDataList.length : 0;
|
||||||
console.log(JSON.stringify(widgetMetaDataList));
|
// console.log(JSON.stringify(widgetMetaDataList));
|
||||||
console.log(widgetCount);
|
// console.log(widgetCount);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
widgetCount > 0 ? (
|
widgetCount > 0 ? (
|
||||||
|
@ -68,7 +68,7 @@ function StepperCard({data}: Props): JSX.Element
|
|||||||
}
|
}
|
||||||
})(StepConnector);
|
})(StepConnector);
|
||||||
|
|
||||||
console.log(`data ${JSON.stringify(data)}`);
|
// console.log(`data ${JSON.stringify(data)}`);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stepper connector={<CustomizedConnector />} activeStep={activeStep} alternativeLabel sx={{paddingBottom: "0px", boxShadow: "none", background: "white"}}>
|
<Stepper connector={<CustomizedConnector />} activeStep={activeStep} alternativeLabel sx={{paddingBottom: "0px", boxShadow: "none", background: "white"}}>
|
||||||
|
@ -68,9 +68,9 @@ function TableCard({title, linkText, linkURL, noRowsFoundHTML, data, dropdownOpt
|
|||||||
const [dropdownLabel, setDropdownLabel] = useState<string>("");
|
const [dropdownLabel, setDropdownLabel] = useState<string>("");
|
||||||
const [dropdownIcon, setDropdownIcon] = useState<string>(openArrowIcon);
|
const [dropdownIcon, setDropdownIcon] = useState<string>(openArrowIcon);
|
||||||
|
|
||||||
console.log(`data: ${JSON.stringify(data?.rows)}`);
|
// console.log(`data: ${JSON.stringify(data?.rows)}`);
|
||||||
console.log(`bool: ${data && data?.columns && !data?.rows}`);
|
// console.log(`bool: ${data && data?.columns && !data?.rows}`);
|
||||||
console.log(`norowsfound: ${noRowsFoundHTML}`);
|
// console.log(`norowsfound: ${noRowsFoundHTML}`);
|
||||||
|
|
||||||
const openDropdown = ({currentTarget}: any) =>
|
const openDropdown = ({currentTarget}: any) =>
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
import {AdornmentType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/AdornmentType";
|
import {AdornmentType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/AdornmentType";
|
||||||
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
|
||||||
|
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
|
||||||
import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
|
import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
|
||||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||||
@ -30,14 +31,38 @@ import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryF
|
|||||||
import {Alert, TablePagination} from "@mui/material";
|
import {Alert, TablePagination} from "@mui/material";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
|
import Divider from "@mui/material/Divider";
|
||||||
import Icon from "@mui/material/Icon";
|
import Icon from "@mui/material/Icon";
|
||||||
import LinearProgress from "@mui/material/LinearProgress";
|
import LinearProgress from "@mui/material/LinearProgress";
|
||||||
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||||
import Menu from "@mui/material/Menu";
|
import Menu from "@mui/material/Menu";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import {DataGridPro, getGridDateOperators, getGridNumericOperators, getGridStringOperators, GridCallbackDetails, GridColDef, GridColumnOrderChangeParams, GridColumnVisibilityModel, GridExportMenuItemProps, GridFilterItem, GridFilterModel, GridRowId, GridRowParams, GridRowsProp, GridSelectionModel, GridSortItem, GridSortModel, GridToolbarColumnsButton, GridToolbarContainer, GridToolbarDensitySelector, GridToolbarExportContainer, GridToolbarFilterButton, MuiEvent} from "@mui/x-data-grid-pro";
|
import Modal from "@mui/material/Modal";
|
||||||
|
import {
|
||||||
|
DataGridPro, getGridDateOperators, getGridNumericOperators, getGridStringOperators,
|
||||||
|
GridCallbackDetails,
|
||||||
|
GridColDef,
|
||||||
|
GridColumnOrderChangeParams,
|
||||||
|
GridColumnVisibilityModel,
|
||||||
|
GridExportMenuItemProps,
|
||||||
|
GridFilterItem,
|
||||||
|
GridFilterModel,
|
||||||
|
GridRowId,
|
||||||
|
GridRowParams,
|
||||||
|
GridRowsProp,
|
||||||
|
GridSelectionModel,
|
||||||
|
GridSortItem,
|
||||||
|
GridSortModel,
|
||||||
|
GridToolbarColumnsButton,
|
||||||
|
GridToolbarContainer,
|
||||||
|
GridToolbarDensitySelector,
|
||||||
|
GridToolbarExportContainer,
|
||||||
|
GridToolbarFilterButton,
|
||||||
|
MuiEvent
|
||||||
|
} from "@mui/x-data-grid-pro";
|
||||||
import {GridFilterOperator} from "@mui/x-data-grid/models/gridFilterOperator";
|
import {GridFilterOperator} from "@mui/x-data-grid/models/gridFilterOperator";
|
||||||
import React, {useCallback, useContext, useEffect, useReducer, useRef, useState} from "react";
|
import React, {useCallback, useContext, useEffect, useReducer, useRef, useState} from "react";
|
||||||
import {Link, useNavigate, useParams, useSearchParams} from "react-router-dom";
|
import {Link, useLocation, useNavigate, useSearchParams} from "react-router-dom";
|
||||||
import QContext from "QContext";
|
import QContext from "QContext";
|
||||||
import DashboardLayout from "qqq/components/DashboardLayout";
|
import DashboardLayout from "qqq/components/DashboardLayout";
|
||||||
import Footer from "qqq/components/Footer";
|
import Footer from "qqq/components/Footer";
|
||||||
@ -45,6 +70,7 @@ import Navbar from "qqq/components/Navbar";
|
|||||||
import {QActionsMenuButton, QCreateNewButton} from "qqq/components/QButtons";
|
import {QActionsMenuButton, QCreateNewButton} from "qqq/components/QButtons";
|
||||||
import MDAlert from "qqq/components/Temporary/MDAlert";
|
import MDAlert from "qqq/components/Temporary/MDAlert";
|
||||||
import MDBox from "qqq/components/Temporary/MDBox";
|
import MDBox from "qqq/components/Temporary/MDBox";
|
||||||
|
import ProcessRun from "qqq/pages/process-run";
|
||||||
import QClient from "qqq/utils/QClient";
|
import QClient from "qqq/utils/QClient";
|
||||||
import QFilterUtils from "qqq/utils/QFilterUtils";
|
import QFilterUtils from "qqq/utils/QFilterUtils";
|
||||||
import QProcessUtils from "qqq/utils/QProcessUtils";
|
import QProcessUtils from "qqq/utils/QProcessUtils";
|
||||||
@ -58,8 +84,14 @@ const ROWS_PER_PAGE_LOCAL_STORAGE_KEY_ROOT = "qqq.rowsPerPage";
|
|||||||
interface Props
|
interface Props
|
||||||
{
|
{
|
||||||
table?: QTableMetaData;
|
table?: QTableMetaData;
|
||||||
|
launchProcess?: QProcessMetaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EntityList.defaultProps = {
|
||||||
|
table: null,
|
||||||
|
launchProcess: null
|
||||||
|
};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Get the default filter to use on the page - either from query string, or
|
** Get the default filter to use on the page - either from query string, or
|
||||||
** local storage, or a default (empty).
|
** local storage, or a default (empty).
|
||||||
@ -109,13 +141,17 @@ function getDefaultFilter(tableMetaData: QTableMetaData, searchParams: URLSearch
|
|||||||
return ({items: []});
|
return ({items: []});
|
||||||
}
|
}
|
||||||
|
|
||||||
function EntityList({table}: Props): JSX.Element
|
function EntityList({table, launchProcess}: Props): JSX.Element
|
||||||
{
|
{
|
||||||
const tableNameParam = useParams().tableName;
|
const tableName = table.name;
|
||||||
const tableName = table === null ? tableNameParam : table.name;
|
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const qController = QClient.getInstance();
|
const qController = QClient.getInstance();
|
||||||
|
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const pathParts = location.pathname.split("/");
|
||||||
|
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
// look for defaults in the local storage //
|
// look for defaults in the local storage //
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
@ -159,6 +195,7 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
const [, setFiltersMenu] = useState(null);
|
const [, setFiltersMenu] = useState(null);
|
||||||
const [actionsMenu, setActionsMenu] = useState(null);
|
const [actionsMenu, setActionsMenu] = useState(null);
|
||||||
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
|
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
|
||||||
|
const [allTableProcesses, setAllTableProcesses] = useState([] as QProcessMetaData[]);
|
||||||
const [pageNumber, setPageNumber] = useState(0);
|
const [pageNumber, setPageNumber] = useState(0);
|
||||||
const [totalRecords, setTotalRecords] = useState(0);
|
const [totalRecords, setTotalRecords] = useState(0);
|
||||||
const [selectedIds, setSelectedIds] = useState([] as string[]);
|
const [selectedIds, setSelectedIds] = useState([] as string[]);
|
||||||
@ -171,6 +208,10 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
const [gridMouseDownX, setGridMouseDownX] = useState(0);
|
const [gridMouseDownX, setGridMouseDownX] = useState(0);
|
||||||
const [gridMouseDownY, setGridMouseDownY] = useState(0);
|
const [gridMouseDownY, setGridMouseDownY] = useState(0);
|
||||||
const [pinnedColumns, setPinnedColumns] = useState({left: ["__check__", "id"]});
|
const [pinnedColumns, setPinnedColumns] = useState({left: ["__check__", "id"]});
|
||||||
|
|
||||||
|
const [activeModalProcess, setActiveModalProcess] = useState(null as QProcessMetaData)
|
||||||
|
const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
|
||||||
|
|
||||||
const instance = useRef({timer: null});
|
const instance = useRef({timer: null});
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -191,6 +232,44 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
|
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
|
||||||
const closeActionsMenu = () => setActionsMenu(null);
|
const closeActionsMenu = () => setActionsMenu(null);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// monitor location changes - if our url looks like a process, then open that process. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// the path for a process looks like: .../table/process //
|
||||||
|
// so if our tableName is in the -2 index, try to open process //
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
if(pathParts[pathParts.length - 2] === tableName)
|
||||||
|
{
|
||||||
|
const processName = pathParts[pathParts.length - 1];
|
||||||
|
const processList = allTableProcesses.filter(p => p.name.endsWith(processName));
|
||||||
|
if(processList.length > 0)
|
||||||
|
{
|
||||||
|
setActiveModalProcess(processList[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log(`Couldn't find process named ${processName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if we didn't open a process... not sure what we do in the table/query use-case //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
setActiveModalProcess(null);
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
const buildQFilter = () =>
|
const buildQFilter = () =>
|
||||||
{
|
{
|
||||||
const qFilter = new QQueryFilter();
|
const qFilter = new QQueryFilter();
|
||||||
@ -315,6 +394,30 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
delete countResults[latestQueryId];
|
delete countResults[latestQueryId];
|
||||||
}, [receivedCountTimestamp]);
|
}, [receivedCountTimestamp]);
|
||||||
|
|
||||||
|
const betweenOperator =
|
||||||
|
{
|
||||||
|
label: "Between",
|
||||||
|
value: "between",
|
||||||
|
getApplyFilterFn: (filterItem: GridFilterItem) =>
|
||||||
|
{
|
||||||
|
if (!Array.isArray(filterItem.value) || filterItem.value.length !== 2)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (filterItem.value[0] == null || filterItem.value[1] == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
return ({value}) =>
|
||||||
|
{
|
||||||
|
return (value !== null && filterItem.value[0] <= value && value <= filterItem.value[1]);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// InputComponent: InputNumberInterval,
|
||||||
|
};
|
||||||
|
|
||||||
const booleanTrueOperator: GridFilterOperator = {
|
const booleanTrueOperator: GridFilterOperator = {
|
||||||
label: "is yes",
|
label: "is yes",
|
||||||
value: "isTrue",
|
value: "isTrue",
|
||||||
@ -546,7 +649,6 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
localStorage.setItem(rowsPerPageLocalStorageKey, JSON.stringify(size));
|
localStorage.setItem(rowsPerPageLocalStorageKey, JSON.stringify(size));
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const handleRowClick = (params: GridRowParams, event: MuiEvent<React.MouseEvent>, details: GridCallbackDetails) =>
|
const handleRowClick = (params: GridRowParams, event: MuiEvent<React.MouseEvent>, details: GridCallbackDetails) =>
|
||||||
{
|
{
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -657,7 +759,14 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
const metaData = await qController.loadMetaData();
|
const metaData = await qController.loadMetaData();
|
||||||
QValueUtils.qInstance = metaData;
|
QValueUtils.qInstance = metaData;
|
||||||
|
|
||||||
setTableProcesses(QProcessUtils.getProcessesForTable(metaData, tableName));
|
setTableProcesses(QProcessUtils.getProcessesForTable(metaData, tableName)); // these are the ones to show in the dropdown
|
||||||
|
setAllTableProcesses(QProcessUtils.getProcessesForTable(metaData, tableName, true)); // these include hidden ones (e.g., to find the bulks)
|
||||||
|
|
||||||
|
if(launchingProcess)
|
||||||
|
{
|
||||||
|
setLaunchingProcess(null);
|
||||||
|
setActiveModalProcess(launchingProcess);
|
||||||
|
}
|
||||||
|
|
||||||
// reset rows to trigger rerender
|
// reset rows to trigger rerender
|
||||||
setRows([]);
|
setRows([]);
|
||||||
@ -766,36 +875,90 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRecordIdsForProcess() : string | QQueryFilter
|
||||||
|
{
|
||||||
|
if (selectFullFilterState === "filter")
|
||||||
|
{
|
||||||
|
return (buildQFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedIds.length > 0)
|
||||||
|
{
|
||||||
|
return (selectedIds.join(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const openModalProcess = (process: QProcessMetaData = null) =>
|
||||||
|
{
|
||||||
|
navigate(`${process.name}${getRecordsQueryString()}`);
|
||||||
|
closeActionsMenu();
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModalProcess = (event: object, reason: string) =>
|
||||||
|
{
|
||||||
|
if(reason === "backdropClick")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// when closing a modal process, navigate up to the table being viewed //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
const newPath = location.pathname.split("/");
|
||||||
|
newPath.pop();
|
||||||
|
navigate(newPath.join("/"));
|
||||||
|
|
||||||
|
updateTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
const openBulkProcess = (processNamePart: "Insert" | "Edit" | "Delete", processLabelPart: "Load" | "Edit" | "Delete") =>
|
||||||
|
{
|
||||||
|
const processList = allTableProcesses.filter(p => p.name.endsWith(`.bulk${processNamePart}`));
|
||||||
|
if(processList.length > 0)
|
||||||
|
{
|
||||||
|
openModalProcess(processList[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setAlertContent(`Could not find Bulk ${processLabelPart} process for this table.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const bulkLoadClicked = () =>
|
const bulkLoadClicked = () =>
|
||||||
{
|
{
|
||||||
navigate(`${tableName}.bulkInsert`);
|
closeActionsMenu();
|
||||||
|
openBulkProcess("Insert", "Load");
|
||||||
};
|
};
|
||||||
|
|
||||||
const bulkEditClicked = () =>
|
const bulkEditClicked = () =>
|
||||||
{
|
{
|
||||||
|
closeActionsMenu();
|
||||||
if (getNoOfSelectedRecords() === 0)
|
if (getNoOfSelectedRecords() === 0)
|
||||||
{
|
{
|
||||||
setAlertContent("No records were selected to Bulk Edit.");
|
setAlertContent("No records were selected to Bulk Edit.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigate(`${tableName}.bulkEdit${getRecordsQueryString()}`);
|
openBulkProcess("Edit", "Edit");
|
||||||
};
|
};
|
||||||
|
|
||||||
const bulkDeleteClicked = () =>
|
const bulkDeleteClicked = () =>
|
||||||
{
|
{
|
||||||
|
closeActionsMenu();
|
||||||
if (getNoOfSelectedRecords() === 0)
|
if (getNoOfSelectedRecords() === 0)
|
||||||
{
|
{
|
||||||
setAlertContent("No records were selected to Bulk Delete.");
|
setAlertContent("No records were selected to Bulk Delete.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
navigate(`${tableName}.bulkDelete${getRecordsQueryString()}`);
|
openBulkProcess("Delete", "Delete");
|
||||||
};
|
};
|
||||||
|
|
||||||
const processClicked = (process: QProcessMetaData) =>
|
const processClicked = (process: QProcessMetaData) =>
|
||||||
{
|
{
|
||||||
// todo - let the process specify that it needs initial rows - err if none selected.
|
// todo - let the process specify that it needs initial rows - err if none selected.
|
||||||
// alternatively, let a process itself have an initial screen to select rows...
|
// alternatively, let a process itself have an initial screen to select rows...
|
||||||
navigate(`${process.name}${getRecordsQueryString()}`);
|
openModalProcess(process);
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -910,12 +1073,24 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
onClose={closeActionsMenu}
|
onClose={closeActionsMenu}
|
||||||
keepMounted
|
keepMounted
|
||||||
>
|
>
|
||||||
<MenuItem onClick={bulkLoadClicked}>Bulk Load</MenuItem>
|
<MenuItem onClick={bulkLoadClicked}>
|
||||||
<MenuItem onClick={bulkEditClicked}>Bulk Edit</MenuItem>
|
<ListItemIcon><Icon>library_add</Icon></ListItemIcon>
|
||||||
<MenuItem onClick={bulkDeleteClicked}>Bulk Delete</MenuItem>
|
Bulk Load
|
||||||
{tableProcesses.length > 0 && <MenuItem divider />}
|
</MenuItem>
|
||||||
|
<MenuItem onClick={bulkEditClicked}>
|
||||||
|
<ListItemIcon><Icon>edit</Icon></ListItemIcon>
|
||||||
|
Bulk Edit
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={bulkDeleteClicked}>
|
||||||
|
<ListItemIcon><Icon>delete</Icon></ListItemIcon>
|
||||||
|
Bulk Delete
|
||||||
|
</MenuItem>
|
||||||
|
{tableProcesses.length > 0 && <Divider />}
|
||||||
{tableProcesses.map((process) => (
|
{tableProcesses.map((process) => (
|
||||||
<MenuItem key={process.name} onClick={() => processClicked(process)}>{process.label}</MenuItem>
|
<MenuItem key={process.name} onClick={() => processClicked(process)}>
|
||||||
|
<ListItemIcon><Icon>{process.iconName ?? "arrow_forward"}</Icon></ListItemIcon>
|
||||||
|
{process.label}
|
||||||
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
@ -1017,13 +1192,17 @@ function EntityList({table}: Props): JSX.Element
|
|||||||
</MDBox>
|
</MDBox>
|
||||||
</Card>
|
</Card>
|
||||||
</MDBox>
|
</MDBox>
|
||||||
|
|
||||||
|
{
|
||||||
|
activeModalProcess &&
|
||||||
|
<Modal open={activeModalProcess !== null} onClose={(event, reason) => closeModalProcess(event, reason)}>
|
||||||
|
<ProcessRun process={activeModalProcess} isModal={true} recordIds={getRecordIdsForProcess()} closeModalHandler={closeModalProcess} />
|
||||||
|
</Modal>
|
||||||
|
}
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</DashboardLayout>
|
</DashboardLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityList.defaultProps = {
|
|
||||||
table: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EntityList;
|
export default EntityList;
|
||||||
|
@ -33,10 +33,13 @@ import DialogActions from "@mui/material/DialogActions";
|
|||||||
import DialogContent from "@mui/material/DialogContent";
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
import DialogContentText from "@mui/material/DialogContentText";
|
import DialogContentText from "@mui/material/DialogContentText";
|
||||||
import DialogTitle from "@mui/material/DialogTitle";
|
import DialogTitle from "@mui/material/DialogTitle";
|
||||||
|
import Divider from "@mui/material/Divider";
|
||||||
import Grid from "@mui/material/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import Icon from "@mui/material/Icon";
|
import Icon from "@mui/material/Icon";
|
||||||
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||||
import Menu from "@mui/material/Menu";
|
import Menu from "@mui/material/Menu";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
import Modal from "@mui/material/Modal";
|
||||||
import React, {useContext, useEffect, useReducer, useState} from "react";
|
import React, {useContext, useEffect, useReducer, useState} from "react";
|
||||||
import {useLocation, useNavigate, useSearchParams} from "react-router-dom";
|
import {useLocation, useNavigate, useSearchParams} from "react-router-dom";
|
||||||
import QContext from "QContext";
|
import QContext from "QContext";
|
||||||
@ -47,6 +50,7 @@ import colors from "qqq/components/Temporary/colors";
|
|||||||
import MDAlert from "qqq/components/Temporary/MDAlert";
|
import MDAlert from "qqq/components/Temporary/MDAlert";
|
||||||
import MDBox from "qqq/components/Temporary/MDBox";
|
import MDBox from "qqq/components/Temporary/MDBox";
|
||||||
import MDTypography from "qqq/components/Temporary/MDTypography";
|
import MDTypography from "qqq/components/Temporary/MDTypography";
|
||||||
|
import ProcessRun from "qqq/pages/process-run";
|
||||||
import QClient from "qqq/utils/QClient";
|
import QClient from "qqq/utils/QClient";
|
||||||
import QProcessUtils from "qqq/utils/QProcessUtils";
|
import QProcessUtils from "qqq/utils/QProcessUtils";
|
||||||
import QTableUtils from "qqq/utils/QTableUtils";
|
import QTableUtils from "qqq/utils/QTableUtils";
|
||||||
@ -59,15 +63,21 @@ interface Props
|
|||||||
{
|
{
|
||||||
id: string;
|
id: string;
|
||||||
table?: QTableMetaData;
|
table?: QTableMetaData;
|
||||||
|
launchProcess?: QProcessMetaData
|
||||||
}
|
}
|
||||||
|
|
||||||
function ViewContents({id, table}: Props): JSX.Element
|
ViewContents.defaultProps = {
|
||||||
|
table: null,
|
||||||
|
launchProcess: null
|
||||||
|
};
|
||||||
|
|
||||||
|
function ViewContents({id, table, launchProcess}: Props): JSX.Element
|
||||||
{
|
{
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const pathParts = location.pathname.split("/");
|
const pathParts = location.pathname.split("/");
|
||||||
const tableName = table ? table.name : pathParts[pathParts.length - 2];
|
const tableName = table.name;
|
||||||
|
|
||||||
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
|
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
|
||||||
const [sectionFieldElements, setSectionFieldElements] = useState(null as Map<string, JSX.Element[]>);
|
const [sectionFieldElements, setSectionFieldElements] = useState(null as Map<string, JSX.Element[]>);
|
||||||
@ -79,13 +89,17 @@ function ViewContents({id, table}: Props): JSX.Element
|
|||||||
const [t1SectionElement, setT1SectionElement] = useState(null as JSX.Element);
|
const [t1SectionElement, setT1SectionElement] = useState(null as JSX.Element);
|
||||||
const [nonT1TableSections, setNonT1TableSections] = useState([] as QTableSection[]);
|
const [nonT1TableSections, setNonT1TableSections] = useState([] as QTableSection[]);
|
||||||
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
|
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
|
||||||
|
const [allTableProcesses, setAllTableProcesses] = useState([] as QProcessMetaData[]);
|
||||||
const [actionsMenu, setActionsMenu] = useState(null);
|
const [actionsMenu, setActionsMenu] = useState(null);
|
||||||
const [tableWidgets, setTableWidgets] = useState([] as QWidgetMetaData[]);
|
const [tableWidgets, setTableWidgets] = useState([] as QWidgetMetaData[]);
|
||||||
const [notFoundMessage, setNotFoundMessage] = useState(null);
|
const [notFoundMessage, setNotFoundMessage] = useState(null);
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const {setPageHeader} = useContext(QContext);
|
const {setPageHeader} = useContext(QContext);
|
||||||
|
const [activeModalProcess, setActiveModalProcess] = useState(null as QProcessMetaData)
|
||||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||||
|
|
||||||
|
const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
|
||||||
|
|
||||||
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
|
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
|
||||||
const closeActionsMenu = () => setActionsMenu(null);
|
const closeActionsMenu = () => setActionsMenu(null);
|
||||||
|
|
||||||
@ -101,9 +115,45 @@ function ViewContents({id, table}: Props): JSX.Element
|
|||||||
setTableWidgets(null);
|
setTableWidgets(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// monitor location changes - if we've clicked a link from viewing one record to viewing another, //
|
||||||
|
// we'll stay in this component, but we'll need to reload all data for the new record. //
|
||||||
|
// if, however, our url looks like a process, then open that process. //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// the path for a process looks like: .../table/id/process //
|
||||||
|
// so if our tableName is in the -3 index, try to open process //
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
if(pathParts[pathParts.length - 3] === tableName)
|
||||||
|
{
|
||||||
|
const processName = pathParts[pathParts.length - 1];
|
||||||
|
const processList = allTableProcesses.filter(p => p.name.endsWith(processName));
|
||||||
|
if(processList.length > 0)
|
||||||
|
{
|
||||||
|
setActiveModalProcess(processList[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log(`Couldn't find process named ${processName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
// if we didn't open a process, assume we need to (re)load //
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
reload();
|
reload();
|
||||||
|
|
||||||
|
setActiveModalProcess(null);
|
||||||
}, [location]);
|
}, [location]);
|
||||||
|
|
||||||
if (!asyncLoadInited)
|
if (!asyncLoadInited)
|
||||||
@ -112,10 +162,10 @@ function ViewContents({id, table}: Props): JSX.Element
|
|||||||
|
|
||||||
(async () =>
|
(async () =>
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// load the table meta-data (if needed) //
|
// load the full table meta-data (the one we took in is a partial) //
|
||||||
//////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
const tableMetaData = table || await qController.loadTableMetaData(tableName);
|
const tableMetaData = await qController.loadTableMetaData(tableName);
|
||||||
setTableMetaData(tableMetaData);
|
setTableMetaData(tableMetaData);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
@ -123,7 +173,15 @@ function ViewContents({id, table}: Props): JSX.Element
|
|||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
const metaData = await qController.loadMetaData();
|
const metaData = await qController.loadMetaData();
|
||||||
QValueUtils.qInstance = metaData;
|
QValueUtils.qInstance = metaData;
|
||||||
setTableProcesses(QProcessUtils.getProcessesForTable(metaData, tableName));
|
const processesForTable = QProcessUtils.getProcessesForTable(metaData, tableName);
|
||||||
|
setTableProcesses(processesForTable);
|
||||||
|
setAllTableProcesses(QProcessUtils.getProcessesForTable(metaData, tableName, true)); // these include hidden ones (e.g., to find the bulks)
|
||||||
|
|
||||||
|
if(launchingProcess)
|
||||||
|
{
|
||||||
|
setLaunchingProcess(null);
|
||||||
|
setActiveModalProcess(launchingProcess);
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////
|
/////////////////////
|
||||||
// load the record //
|
// load the record //
|
||||||
@ -236,8 +294,7 @@ function ViewContents({id, table}: Props): JSX.Element
|
|||||||
|
|
||||||
function processClicked(process: QProcessMetaData)
|
function processClicked(process: QProcessMetaData)
|
||||||
{
|
{
|
||||||
const path = `${pathParts.slice(0, -1).join("/")}/${process.name}?recordIds=${id}`;
|
openModalProcess(process);
|
||||||
navigate(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderActionsMenu = (
|
const renderActionsMenu = (
|
||||||
@ -255,22 +312,50 @@ function ViewContents({id, table}: Props): JSX.Element
|
|||||||
onClose={closeActionsMenu}
|
onClose={closeActionsMenu}
|
||||||
keepMounted
|
keepMounted
|
||||||
>
|
>
|
||||||
<MenuItem onClick={() => navigate("edit")}>Edit</MenuItem>
|
<MenuItem onClick={() => navigate("edit")}>
|
||||||
|
<ListItemIcon><Icon>edit</Icon></ListItemIcon>
|
||||||
|
Edit
|
||||||
|
</MenuItem>
|
||||||
<MenuItem onClick={() =>
|
<MenuItem onClick={() =>
|
||||||
{
|
{
|
||||||
setActionsMenu(null);
|
setActionsMenu(null);
|
||||||
handleClickDeleteButton();
|
handleClickDeleteButton();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<ListItemIcon><Icon>delete</Icon></ListItemIcon>
|
||||||
Delete
|
Delete
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{tableProcesses.length > 0 && <MenuItem divider />}
|
{tableProcesses.length > 0 && <Divider />}
|
||||||
{tableProcesses.map((process) => (
|
{tableProcesses.map((process) => (
|
||||||
<MenuItem key={process.name} onClick={() => processClicked(process)}>{process.label}</MenuItem>
|
<MenuItem key={process.name} onClick={() => processClicked(process)}>
|
||||||
|
<ListItemIcon><Icon>{process.iconName ?? "arrow_forward"}</Icon></ListItemIcon>
|
||||||
|
{process.label}
|
||||||
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const openModalProcess = (process: QProcessMetaData = null) =>
|
||||||
|
{
|
||||||
|
navigate(process.name);
|
||||||
|
closeActionsMenu();
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModalProcess = (event: object, reason: string) =>
|
||||||
|
{
|
||||||
|
if(reason === "backdropClick")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// when closing a modal process, navigate up to the record being viewed //
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
const newPath = location.pathname.split("/");
|
||||||
|
newPath.pop();
|
||||||
|
navigate(newPath.join("/"));
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
notFoundMessage
|
notFoundMessage
|
||||||
?
|
?
|
||||||
@ -364,13 +449,17 @@ function ViewContents({id, table}: Props): JSX.Element
|
|||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
{
|
||||||
|
activeModalProcess &&
|
||||||
|
<Modal open={activeModalProcess !== null} onClose={(event, reason) => closeModalProcess(event, reason)}>
|
||||||
|
<ProcessRun process={activeModalProcess} isModal={true} recordIds={id} closeModalHandler={closeModalProcess} />
|
||||||
|
</Modal>
|
||||||
|
}
|
||||||
|
|
||||||
</MDBox>
|
</MDBox>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewContents.defaultProps = {
|
|
||||||
table: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ViewContents;
|
export default ViewContents;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
|
||||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||||
import Grid from "@mui/material/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import {useParams} from "react-router-dom";
|
import {useParams} from "react-router-dom";
|
||||||
@ -29,9 +30,10 @@ import ViewContents from "./components/ViewContents";
|
|||||||
interface Props
|
interface Props
|
||||||
{
|
{
|
||||||
table?: QTableMetaData;
|
table?: QTableMetaData;
|
||||||
|
launchProcess?: QProcessMetaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
function EntityView({table}: Props): JSX.Element
|
function EntityView({table, launchProcess}: Props): JSX.Element
|
||||||
{
|
{
|
||||||
const {id} = useParams();
|
const {id} = useParams();
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ function EntityView({table}: Props): JSX.Element
|
|||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<MDBox mb={3}>
|
<MDBox mb={3}>
|
||||||
<ViewContents id={id} />
|
<ViewContents table={table} id={id} launchProcess={launchProcess}/>
|
||||||
</MDBox>
|
</MDBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -52,6 +54,7 @@ function EntityView({table}: Props): JSX.Element
|
|||||||
|
|
||||||
EntityView.defaultProps = {
|
EntityView.defaultProps = {
|
||||||
table: null,
|
table: null,
|
||||||
|
launchProcess: null
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EntityView;
|
export default EntityView;
|
||||||
|
@ -31,6 +31,7 @@ import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobEr
|
|||||||
import {QJobRunning} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobRunning";
|
import {QJobRunning} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobRunning";
|
||||||
import {QJobStarted} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobStarted";
|
import {QJobStarted} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobStarted";
|
||||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||||
|
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
|
||||||
import {Button, CircularProgress, Icon, TablePagination} from "@mui/material";
|
import {Button, CircularProgress, Icon, TablePagination} from "@mui/material";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
@ -65,13 +66,16 @@ interface Props
|
|||||||
{
|
{
|
||||||
process?: QProcessMetaData;
|
process?: QProcessMetaData;
|
||||||
defaultProcessValues?: any;
|
defaultProcessValues?: any;
|
||||||
|
isModal?: boolean
|
||||||
|
recordIds?: string | QQueryFilter
|
||||||
|
closeModalHandler?: (event: object, reason: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const INITIAL_RETRY_MILLIS = 1_500;
|
const INITIAL_RETRY_MILLIS = 1_500;
|
||||||
const RETRY_MAX_MILLIS = 12_000;
|
const RETRY_MAX_MILLIS = 12_000;
|
||||||
const BACKOFF_AMOUNT = 1.5;
|
const BACKOFF_AMOUNT = 1.5;
|
||||||
|
|
||||||
function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
function ProcessRun({process, defaultProcessValues, isModal, recordIds, closeModalHandler}: Props): JSX.Element
|
||||||
{
|
{
|
||||||
const processNameParam = useParams().processName;
|
const processNameParam = useParams().processName;
|
||||||
const processName = process === null ? processNameParam : process.name;
|
const processName = process === null ? processNameParam : process.name;
|
||||||
@ -248,6 +252,13 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
</MDTypography>
|
</MDTypography>
|
||||||
|
<MDBox component="div" py={3}>
|
||||||
|
<Grid container justifyContent="flex-end" spacing={3}>
|
||||||
|
{isModal ? <QCancelButton onClickHandler={handleCancelClicked} disabled={false} label="Close" />
|
||||||
|
: <QCancelButton onClickHandler={handleCancelClicked} disabled={false} />
|
||||||
|
}
|
||||||
|
</Grid>
|
||||||
|
</MDBox>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -294,7 +305,10 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MDTypography variation="h5" component="div" fontWeight="bold">{step?.label}</MDTypography>
|
<MDTypography variation="h5" component="div" fontWeight="bold">
|
||||||
|
{isModal ? `${process.label}: ` : ""}
|
||||||
|
{step?.label}
|
||||||
|
</MDTypography>
|
||||||
{step.components && (
|
{step.components && (
|
||||||
step.components.map((component: QFrontendComponent, index: number) => (
|
step.components.map((component: QFrontendComponent, index: number) => (
|
||||||
// eslint-disable-next-line react/no-array-index-key
|
// eslint-disable-next-line react/no-array-index-key
|
||||||
@ -839,6 +853,19 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
// queryStringPairsForInit.push("recordsParam=filterId");
|
// queryStringPairsForInit.push("recordsParam=filterId");
|
||||||
// queryStringPairsForInit.push(`filterId=${urlSearchParams.get("filterId")}`);
|
// queryStringPairsForInit.push(`filterId=${urlSearchParams.get("filterId")}`);
|
||||||
// }
|
// }
|
||||||
|
else if(recordIds)
|
||||||
|
{
|
||||||
|
if(typeof recordIds === "string")
|
||||||
|
{
|
||||||
|
queryStringPairsForInit.push("recordsParam=recordIds");
|
||||||
|
queryStringPairsForInit.push(`recordIds=${recordIds}`);
|
||||||
|
}
|
||||||
|
else if (recordIds instanceof QQueryFilter)
|
||||||
|
{
|
||||||
|
queryStringPairsForInit.push("recordsParam=filterJSON");
|
||||||
|
queryStringPairsForInit.push(`filterJSON=${JSON.stringify(recordIds)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -964,6 +991,12 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
|
|
||||||
const handleCancelClicked = () =>
|
const handleCancelClicked = () =>
|
||||||
{
|
{
|
||||||
|
if(isModal && closeModalHandler)
|
||||||
|
{
|
||||||
|
closeModalHandler(null, "cancelClicked");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const pathParts = location.pathname.split(/\//);
|
const pathParts = location.pathname.split(/\//);
|
||||||
pathParts.pop();
|
pathParts.pop();
|
||||||
const path = pathParts.join("/");
|
const path = pathParts.join("/");
|
||||||
@ -971,8 +1004,8 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mainCardStyles: any = {};
|
const mainCardStyles: any = {};
|
||||||
mainCardStyles.minHeight = "calc(100vh - 400px)";
|
mainCardStyles.minHeight = `calc(100vh - ${isModal ? 150 : 400}px)`;
|
||||||
if (!processError && (qJobRunning || activeStep === null))
|
if (!processError && (qJobRunning || activeStep === null) && !isModal)
|
||||||
{
|
{
|
||||||
mainCardStyles.background = "none";
|
mainCardStyles.background = "none";
|
||||||
mainCardStyles.boxShadow = "none";
|
mainCardStyles.boxShadow = "none";
|
||||||
@ -994,102 +1027,124 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
nextButtonIcon = "check";
|
nextButtonIcon = "check";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const body = (
|
||||||
<BaseLayout>
|
<MDBox py={3} mb={20}>
|
||||||
<MDBox py={3} mb={20}>
|
<Grid container justifyContent="center" alignItems="center" sx={{height: "100%", mt: 8}}>
|
||||||
<Grid container justifyContent="center" alignItems="center" sx={{height: "100%", mt: 8}}>
|
<Grid item xs={12} lg={10} xl={8}>
|
||||||
<Grid item xs={12} lg={10} xl={8}>
|
<Formik
|
||||||
<Formik
|
enableReinitialize
|
||||||
enableReinitialize
|
initialValues={initialValues}
|
||||||
initialValues={initialValues}
|
validationSchema={validationScheme}
|
||||||
validationSchema={validationScheme}
|
validation={validationFunction}
|
||||||
validation={validationFunction}
|
onSubmit={handleSubmit}
|
||||||
onSubmit={handleSubmit}
|
>
|
||||||
>
|
{({
|
||||||
{({
|
values, errors, touched, isSubmitting, setFieldValue,
|
||||||
values, errors, touched, isSubmitting, setFieldValue,
|
}) => (
|
||||||
}) => (
|
<Form id={formId} autoComplete="off">
|
||||||
<Form id={formId} autoComplete="off">
|
<Card sx={mainCardStyles}>
|
||||||
<Card sx={mainCardStyles}>
|
<MDBox mx={2} mt={-3}>
|
||||||
<MDBox mx={2} mt={-3}>
|
<Stepper activeStep={activeStepIndex} alternativeLabel>
|
||||||
<Stepper activeStep={activeStepIndex} alternativeLabel>
|
{steps.map((step) => (
|
||||||
{steps.map((step) => (
|
<Step key={step.name}>
|
||||||
<Step key={step.name}>
|
<StepLabel>{step.label}</StepLabel>
|
||||||
<StepLabel>{step.label}</StepLabel>
|
</Step>
|
||||||
</Step>
|
))}
|
||||||
))}
|
</Stepper>
|
||||||
</Stepper>
|
</MDBox>
|
||||||
</MDBox>
|
|
||||||
|
|
||||||
<MDBox p={3}>
|
<MDBox p={3}>
|
||||||
<MDBox>
|
<MDBox>
|
||||||
{/***************************************************************************
|
{/***************************************************************************
|
||||||
** step content - e.g., the appropriate form or other screen for the step **
|
** step content - e.g., the appropriate form or other screen for the step **
|
||||||
***************************************************************************/}
|
***************************************************************************/}
|
||||||
{getDynamicStepContent(
|
{getDynamicStepContent(
|
||||||
activeStepIndex,
|
activeStepIndex,
|
||||||
activeStep,
|
activeStep,
|
||||||
{
|
{
|
||||||
values,
|
values,
|
||||||
touched,
|
touched,
|
||||||
formFields,
|
formFields,
|
||||||
errors,
|
errors,
|
||||||
},
|
},
|
||||||
processError,
|
processError,
|
||||||
processValues,
|
processValues,
|
||||||
recordConfig,
|
recordConfig,
|
||||||
setFieldValue,
|
setFieldValue,
|
||||||
)}
|
)}
|
||||||
{/********************************
|
{/********************************
|
||||||
** back &| next/submit buttons **
|
** back &| next/submit buttons **
|
||||||
********************************/}
|
********************************/}
|
||||||
<MDBox mt={6} width="100%" display="flex" justifyContent="space-between">
|
<MDBox mt={6} width="100%" display="flex" justifyContent="space-between">
|
||||||
{true || activeStepIndex === 0 ? (
|
{true || activeStepIndex === 0 ? (
|
||||||
<MDBox />
|
<MDBox />
|
||||||
) : (
|
) : (
|
||||||
<MDButton variant="gradient" color="light" onClick={handleBack}>back</MDButton>
|
<MDButton variant="gradient" color="light" onClick={handleBack}>back</MDButton>
|
||||||
)}
|
)}
|
||||||
{processError || qJobRunning || !activeStep ? (
|
{processError || qJobRunning || !activeStep ? (
|
||||||
<MDBox />
|
<MDBox />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{formError && (
|
{formError && (
|
||||||
<MDTypography component="div" variant="caption" color="error" fontWeight="regular" align="right" fullWidth>
|
<MDTypography component="div" variant="caption" color="error" fontWeight="regular" align="right" fullWidth>
|
||||||
{formError}
|
{formError}
|
||||||
</MDTypography>
|
</MDTypography>
|
||||||
)}
|
)}
|
||||||
{
|
{
|
||||||
noMoreSteps && <QCancelButton onClickHandler={handleCancelClicked} label="Return" iconName="arrow_back" disabled={isSubmitting} />
|
noMoreSteps && <QCancelButton
|
||||||
}
|
onClickHandler={handleCancelClicked}
|
||||||
{
|
label={isModal ? "Close" : "Return"}
|
||||||
!noMoreSteps && (
|
iconName={isModal ? "cancel" : "arrow_back"}
|
||||||
<MDBox component="div" py={3}>
|
disabled={isSubmitting} />
|
||||||
<Grid container justifyContent="flex-end" spacing={3}>
|
}
|
||||||
<QCancelButton onClickHandler={handleCancelClicked} disabled={isSubmitting} />
|
{
|
||||||
<QSubmitButton label={nextButtonLabel} iconName={nextButtonIcon} disabled={isSubmitting} />
|
!noMoreSteps && (
|
||||||
</Grid>
|
<MDBox component="div" py={3}>
|
||||||
</MDBox>
|
<Grid container justifyContent="flex-end" spacing={3}>
|
||||||
)
|
<QCancelButton onClickHandler={handleCancelClicked} disabled={isSubmitting} />
|
||||||
}
|
<QSubmitButton label={nextButtonLabel} iconName={nextButtonIcon} disabled={isSubmitting} />
|
||||||
</>
|
</Grid>
|
||||||
)}
|
</MDBox>
|
||||||
</MDBox>
|
)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</MDBox>
|
</MDBox>
|
||||||
</MDBox>
|
</MDBox>
|
||||||
</Card>
|
</MDBox>
|
||||||
</Form>
|
</Card>
|
||||||
)}
|
</Form>
|
||||||
</Formik>
|
)}
|
||||||
</Grid>
|
</Formik>
|
||||||
</Grid>
|
</Grid>
|
||||||
</MDBox>
|
</Grid>
|
||||||
</BaseLayout>
|
</MDBox>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if(isModal)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<Box sx={{position: "absolute", overflowY: "auto", maxHeight: "100%", width: "100%"}}>
|
||||||
|
{body}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<BaseLayout>
|
||||||
|
{body}
|
||||||
|
</BaseLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessRun.defaultProps = {
|
ProcessRun.defaultProps = {
|
||||||
process: null,
|
process: null,
|
||||||
defaultProcessValues: {}
|
defaultProcessValues: {},
|
||||||
|
isModal: false,
|
||||||
|
recordIds: null,
|
||||||
|
closeModalHandler: null
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ProcessRun;
|
export default ProcessRun;
|
||||||
|
@ -136,3 +136,11 @@
|
|||||||
{
|
{
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* google drive picker - make it be above our modal */
|
||||||
|
.picker,
|
||||||
|
.picker.picker-dialog-bg,
|
||||||
|
.picker.picker-dialog
|
||||||
|
{
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user