diff --git a/src/App.tsx b/src/App.tsx
index ca49665..c9ccdc5 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -269,13 +269,21 @@ export default function App()
name: process.label,
key: process.name,
route: `${path}/${process.name}`,
- component: ,
+ component: ,
+ });
+
+ routeList.push({
+ name: process.label,
+ key: `${app.name}/${process.name}`,
+ route: `${path}/:id/${process.name}`,
+ component: ,
});
});
const reportsForTable = QProcessUtils.getReportsForTable(metaData, table.name, true);
reportsForTable.forEach((report) =>
{
+ // todo - do we need some table/report routes here, that would go to EntityList and/or EntityView
routeList.push({
name: report.label,
key: report.name,
diff --git a/src/qqq/components/DashboardWidgets.tsx b/src/qqq/components/DashboardWidgets.tsx
index ccbccfb..ae7d4bf 100644
--- a/src/qqq/components/DashboardWidgets.tsx
+++ b/src/qqq/components/DashboardWidgets.tsx
@@ -102,8 +102,8 @@ function DashboardWidgets({widgetMetaDataList, entityPrimaryKey}: Props): JSX.El
};
const widgetCount = widgetMetaDataList ? widgetMetaDataList.length : 0;
- console.log(JSON.stringify(widgetMetaDataList));
- console.log(widgetCount);
+ // console.log(JSON.stringify(widgetMetaDataList));
+ // console.log(widgetCount);
return (
widgetCount > 0 ? (
diff --git a/src/qqq/pages/dashboards/Widgets/StepperCard.tsx b/src/qqq/pages/dashboards/Widgets/StepperCard.tsx
index 748f649..a2a121f 100644
--- a/src/qqq/pages/dashboards/Widgets/StepperCard.tsx
+++ b/src/qqq/pages/dashboards/Widgets/StepperCard.tsx
@@ -68,7 +68,7 @@ function StepperCard({data}: Props): JSX.Element
}
})(StepConnector);
- console.log(`data ${JSON.stringify(data)}`);
+ // console.log(`data ${JSON.stringify(data)}`);
return (
} activeStep={activeStep} alternativeLabel sx={{paddingBottom: "0px", boxShadow: "none", background: "white"}}>
diff --git a/src/qqq/pages/dashboards/Widgets/TableCard.tsx b/src/qqq/pages/dashboards/Widgets/TableCard.tsx
index 2da377f..d2d653d 100644
--- a/src/qqq/pages/dashboards/Widgets/TableCard.tsx
+++ b/src/qqq/pages/dashboards/Widgets/TableCard.tsx
@@ -68,9 +68,9 @@ function TableCard({title, linkText, linkURL, noRowsFoundHTML, data, dropdownOpt
const [dropdownLabel, setDropdownLabel] = useState("");
const [dropdownIcon, setDropdownIcon] = useState(openArrowIcon);
- console.log(`data: ${JSON.stringify(data?.rows)}`);
- console.log(`bool: ${data && data?.columns && !data?.rows}`);
- console.log(`norowsfound: ${noRowsFoundHTML}`);
+ // console.log(`data: ${JSON.stringify(data?.rows)}`);
+ // console.log(`bool: ${data && data?.columns && !data?.rows}`);
+ // console.log(`norowsfound: ${noRowsFoundHTML}`);
const openDropdown = ({currentTarget}: any) =>
{
diff --git a/src/qqq/pages/entity-list/index.tsx b/src/qqq/pages/entity-list/index.tsx
index eee170a..44cc555 100644
--- a/src/qqq/pages/entity-list/index.tsx
+++ b/src/qqq/pages/entity-list/index.tsx
@@ -21,6 +21,7 @@
import {AdornmentType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/AdornmentType";
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 {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
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 Button from "@mui/material/Button";
import Card from "@mui/material/Card";
+import Divider from "@mui/material/Divider";
import Icon from "@mui/material/Icon";
import LinearProgress from "@mui/material/LinearProgress";
+import ListItemIcon from "@mui/material/ListItemIcon";
import Menu from "@mui/material/Menu";
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 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 DashboardLayout from "qqq/components/DashboardLayout";
import Footer from "qqq/components/Footer";
@@ -45,6 +70,7 @@ import Navbar from "qqq/components/Navbar";
import {QActionsMenuButton, QCreateNewButton} from "qqq/components/QButtons";
import MDAlert from "qqq/components/Temporary/MDAlert";
import MDBox from "qqq/components/Temporary/MDBox";
+import ProcessRun from "qqq/pages/process-run";
import QClient from "qqq/utils/QClient";
import QFilterUtils from "qqq/utils/QFilterUtils";
import QProcessUtils from "qqq/utils/QProcessUtils";
@@ -58,8 +84,14 @@ const ROWS_PER_PAGE_LOCAL_STORAGE_KEY_ROOT = "qqq.rowsPerPage";
interface Props
{
table?: QTableMetaData;
+ launchProcess?: QProcessMetaData;
}
+EntityList.defaultProps = {
+ table: null,
+ launchProcess: null
+};
+
/*******************************************************************************
** Get the default filter to use on the page - either from query string, or
** local storage, or a default (empty).
@@ -109,13 +141,17 @@ function getDefaultFilter(tableMetaData: QTableMetaData, searchParams: URLSearch
return ({items: []});
}
-function EntityList({table}: Props): JSX.Element
+function EntityList({table, launchProcess}: Props): JSX.Element
{
- const tableNameParam = useParams().tableName;
- const tableName = table === null ? tableNameParam : table.name;
+ const tableName = table.name;
const [searchParams] = useSearchParams();
const qController = QClient.getInstance();
+ const location = useLocation();
+ const navigate = useNavigate();
+
+ const pathParts = location.pathname.split("/");
+
////////////////////////////////////////////
// look for defaults in the local storage //
////////////////////////////////////////////
@@ -159,6 +195,7 @@ function EntityList({table}: Props): JSX.Element
const [, setFiltersMenu] = useState(null);
const [actionsMenu, setActionsMenu] = useState(null);
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
+ const [allTableProcesses, setAllTableProcesses] = useState([] as QProcessMetaData[]);
const [pageNumber, setPageNumber] = useState(0);
const [totalRecords, setTotalRecords] = useState(0);
const [selectedIds, setSelectedIds] = useState([] as string[]);
@@ -171,6 +208,10 @@ function EntityList({table}: Props): JSX.Element
const [gridMouseDownX, setGridMouseDownX] = useState(0);
const [gridMouseDownY, setGridMouseDownY] = useState(0);
const [pinnedColumns, setPinnedColumns] = useState({left: ["__check__", "id"]});
+
+ const [activeModalProcess, setActiveModalProcess] = useState(null as QProcessMetaData)
+ const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
+
const instance = useRef({timer: null});
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -191,6 +232,44 @@ function EntityList({table}: Props): JSX.Element
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
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 qFilter = new QQueryFilter();
@@ -315,6 +394,30 @@ function EntityList({table}: Props): JSX.Element
delete countResults[latestQueryId];
}, [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 = {
label: "is yes",
value: "isTrue",
@@ -546,7 +649,6 @@ function EntityList({table}: Props): JSX.Element
localStorage.setItem(rowsPerPageLocalStorageKey, JSON.stringify(size));
};
- const navigate = useNavigate();
const handleRowClick = (params: GridRowParams, event: MuiEvent, details: GridCallbackDetails) =>
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -657,7 +759,14 @@ function EntityList({table}: Props): JSX.Element
const metaData = await qController.loadMetaData();
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
setRows([]);
@@ -766,36 +875,90 @@ function EntityList({table}: Props): JSX.Element
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 = () =>
{
- navigate(`${tableName}.bulkInsert`);
+ closeActionsMenu();
+ openBulkProcess("Insert", "Load");
};
const bulkEditClicked = () =>
{
+ closeActionsMenu();
if (getNoOfSelectedRecords() === 0)
{
setAlertContent("No records were selected to Bulk Edit.");
return;
}
- navigate(`${tableName}.bulkEdit${getRecordsQueryString()}`);
+ openBulkProcess("Edit", "Edit");
};
const bulkDeleteClicked = () =>
{
+ closeActionsMenu();
if (getNoOfSelectedRecords() === 0)
{
setAlertContent("No records were selected to Bulk Delete.");
return;
}
- navigate(`${tableName}.bulkDelete${getRecordsQueryString()}`);
+ openBulkProcess("Delete", "Delete");
};
const processClicked = (process: QProcessMetaData) =>
{
// 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...
- navigate(`${process.name}${getRecordsQueryString()}`);
+ openModalProcess(process);
};
// @ts-ignore
@@ -910,12 +1073,24 @@ function EntityList({table}: Props): JSX.Element
onClose={closeActionsMenu}
keepMounted
>
-
-
-
- {tableProcesses.length > 0 && }
+
+
+
+ {tableProcesses.length > 0 && }
{tableProcesses.map((process) => (
-
+
))}
);
@@ -1017,13 +1192,17 @@ function EntityList({table}: Props): JSX.Element
+
+ {
+ activeModalProcess &&
+ closeModalProcess(event, reason)}>
+
+
+ }
+
);
}
-EntityList.defaultProps = {
- table: null,
-};
-
export default EntityList;
diff --git a/src/qqq/pages/entity-view/components/ViewContents/index.tsx b/src/qqq/pages/entity-view/components/ViewContents/index.tsx
index af6a99d..b2836d8 100644
--- a/src/qqq/pages/entity-view/components/ViewContents/index.tsx
+++ b/src/qqq/pages/entity-view/components/ViewContents/index.tsx
@@ -33,10 +33,13 @@ import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
+import Divider from "@mui/material/Divider";
import Grid from "@mui/material/Grid";
import Icon from "@mui/material/Icon";
+import ListItemIcon from "@mui/material/ListItemIcon";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
+import Modal from "@mui/material/Modal";
import React, {useContext, useEffect, useReducer, useState} from "react";
import {useLocation, useNavigate, useSearchParams} from "react-router-dom";
import QContext from "QContext";
@@ -47,6 +50,7 @@ import colors from "qqq/components/Temporary/colors";
import MDAlert from "qqq/components/Temporary/MDAlert";
import MDBox from "qqq/components/Temporary/MDBox";
import MDTypography from "qqq/components/Temporary/MDTypography";
+import ProcessRun from "qqq/pages/process-run";
import QClient from "qqq/utils/QClient";
import QProcessUtils from "qqq/utils/QProcessUtils";
import QTableUtils from "qqq/utils/QTableUtils";
@@ -59,15 +63,21 @@ interface Props
{
id: string;
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 navigate = useNavigate();
const pathParts = location.pathname.split("/");
- const tableName = table ? table.name : pathParts[pathParts.length - 2];
+ const tableName = table.name;
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
const [sectionFieldElements, setSectionFieldElements] = useState(null as Map);
@@ -79,13 +89,17 @@ function ViewContents({id, table}: Props): JSX.Element
const [t1SectionElement, setT1SectionElement] = useState(null as JSX.Element);
const [nonT1TableSections, setNonT1TableSections] = useState([] as QTableSection[]);
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
+ const [allTableProcesses, setAllTableProcesses] = useState([] as QProcessMetaData[]);
const [actionsMenu, setActionsMenu] = useState(null);
const [tableWidgets, setTableWidgets] = useState([] as QWidgetMetaData[]);
const [notFoundMessage, setNotFoundMessage] = useState(null);
const [searchParams] = useSearchParams();
const {setPageHeader} = useContext(QContext);
+ const [activeModalProcess, setActiveModalProcess] = useState(null as QProcessMetaData)
const [, forceUpdate] = useReducer((x) => x + 1, 0);
+ const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
+
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
const closeActionsMenu = () => setActionsMenu(null);
@@ -101,9 +115,45 @@ function ViewContents({id, table}: Props): JSX.Element
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(() =>
{
+ 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();
+
+ setActiveModalProcess(null);
}, [location]);
if (!asyncLoadInited)
@@ -112,10 +162,10 @@ function ViewContents({id, table}: Props): JSX.Element
(async () =>
{
- //////////////////////////////////////////
- // load the table meta-data (if needed) //
- //////////////////////////////////////////
- const tableMetaData = table || await qController.loadTableMetaData(tableName);
+ /////////////////////////////////////////////////////////////////////
+ // load the full table meta-data (the one we took in is a partial) //
+ /////////////////////////////////////////////////////////////////////
+ const tableMetaData = await qController.loadTableMetaData(tableName);
setTableMetaData(tableMetaData);
//////////////////////////////////////////////////////////////////
@@ -123,7 +173,15 @@ function ViewContents({id, table}: Props): JSX.Element
//////////////////////////////////////////////////////////////////
const metaData = await qController.loadMetaData();
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 //
@@ -236,8 +294,7 @@ function ViewContents({id, table}: Props): JSX.Element
function processClicked(process: QProcessMetaData)
{
- const path = `${pathParts.slice(0, -1).join("/")}/${process.name}?recordIds=${id}`;
- navigate(path);
+ openModalProcess(process);
}
const renderActionsMenu = (
@@ -255,22 +312,50 @@ function ViewContents({id, table}: Props): JSX.Element
onClose={closeActionsMenu}
keepMounted
>
-
+
- {tableProcesses.length > 0 && }
+ {tableProcesses.length > 0 && }
{tableProcesses.map((process) => (
-
+
))}
);
+ 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 (
notFoundMessage
?
@@ -364,13 +449,17 @@ function ViewContents({id, table}: Props): JSX.Element
+
+ {
+ activeModalProcess &&
+ closeModalProcess(event, reason)}>
+
+
+ }
+
);
}
-ViewContents.defaultProps = {
- table: null,
-};
-
export default ViewContents;
diff --git a/src/qqq/pages/entity-view/index.tsx b/src/qqq/pages/entity-view/index.tsx
index 90bd13f..14e88ef 100644
--- a/src/qqq/pages/entity-view/index.tsx
+++ b/src/qqq/pages/entity-view/index.tsx
@@ -19,6 +19,7 @@
* along with this program. If not, see .
*/
+import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import Grid from "@mui/material/Grid";
import {useParams} from "react-router-dom";
@@ -29,9 +30,10 @@ import ViewContents from "./components/ViewContents";
interface Props
{
table?: QTableMetaData;
+ launchProcess?: QProcessMetaData;
}
-function EntityView({table}: Props): JSX.Element
+function EntityView({table, launchProcess}: Props): JSX.Element
{
const {id} = useParams();
@@ -41,7 +43,7 @@ function EntityView({table}: Props): JSX.Element
-
+
@@ -52,6 +54,7 @@ function EntityView({table}: Props): JSX.Element
EntityView.defaultProps = {
table: null,
+ launchProcess: null
};
export default EntityView;
diff --git a/src/qqq/pages/process-run/index.tsx b/src/qqq/pages/process-run/index.tsx
index 0915fc5..19a03e6 100644
--- a/src/qqq/pages/process-run/index.tsx
+++ b/src/qqq/pages/process-run/index.tsx
@@ -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 {QJobStarted} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobStarted";
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 Box from "@mui/material/Box";
import Card from "@mui/material/Card";
@@ -65,13 +66,16 @@ interface Props
{
process?: QProcessMetaData;
defaultProcessValues?: any;
+ isModal?: boolean
+ recordIds?: string | QQueryFilter
+ closeModalHandler?: (event: object, reason: string) => void
}
const INITIAL_RETRY_MILLIS = 1_500;
const RETRY_MAX_MILLIS = 12_000;
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 processName = process === null ? processNameParam : process.name;
@@ -248,6 +252,13 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
)
}
+
+
+ {isModal ?
+ :
+ }
+
+
>
);
}
@@ -294,7 +305,10 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
return (
<>
- {step?.label}
+
+ {isModal ? `${process.label}: ` : ""}
+ {step?.label}
+
{step.components && (
step.components.map((component: QFrontendComponent, index: number) => (
// 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(`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
{
@@ -964,6 +991,12 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
const handleCancelClicked = () =>
{
+ if(isModal && closeModalHandler)
+ {
+ closeModalHandler(null, "cancelClicked");
+ return;
+ }
+
const pathParts = location.pathname.split(/\//);
pathParts.pop();
const path = pathParts.join("/");
@@ -971,8 +1004,8 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
};
const mainCardStyles: any = {};
- mainCardStyles.minHeight = "calc(100vh - 400px)";
- if (!processError && (qJobRunning || activeStep === null))
+ mainCardStyles.minHeight = `calc(100vh - ${isModal ? 150 : 400}px)`;
+ if (!processError && (qJobRunning || activeStep === null) && !isModal)
{
mainCardStyles.background = "none";
mainCardStyles.boxShadow = "none";
@@ -994,102 +1027,124 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
nextButtonIcon = "check";
}
- return (
-
-
-
-
-
- {({
- values, errors, touched, isSubmitting, setFieldValue,
- }) => (
-
+ )}
+
-
-
+
+
);
+
+ if(isModal)
+ {
+ return (
+
+ {body}
+
+ );
+ }
+ else
+ {
+ return (
+
+ {body}
+
+ );
+ }
}
ProcessRun.defaultProps = {
process: null,
- defaultProcessValues: {}
+ defaultProcessValues: {},
+ isModal: false,
+ recordIds: null,
+ closeModalHandler: null
};
export default ProcessRun;
diff --git a/src/qqq/styles/qqq-override-styles.css b/src/qqq/styles/qqq-override-styles.css
index ee3be50..7c7150a 100644
--- a/src/qqq/styles/qqq-override-styles.css
+++ b/src/qqq/styles/qqq-override-styles.css
@@ -136,3 +136,11 @@
{
align-items: flex-end;
}
+
+/* google drive picker - make it be above our modal */
+.picker,
+.picker.picker-dialog-bg,
+.picker.picker-dialog
+{
+ z-index: 99999;
+}