diff --git a/src/App.tsx b/src/App.tsx index b0177f8..13e32f8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -49,6 +49,7 @@ import EntityEdit from "qqq/pages/entity-edit"; import EntityList from "qqq/pages/entity-list"; import EntityView from "qqq/pages/entity-view"; import ProcessRun from "qqq/pages/process-run"; +import ReportRun from "qqq/pages/process-run/ReportRun"; import QClient from "qqq/utils/QClient"; import QProcessUtils from "qqq/utils/QProcessUtils"; @@ -270,6 +271,17 @@ export default function App() component: , }); }); + + const reportsForTable = QProcessUtils.getReportsForTable(metaData, table.name, true); + reportsForTable.forEach((report) => + { + routeList.push({ + name: report.label, + key: report.name, + route: `${path}/${report.name}`, + component: , + }); + }); } else if (app.type === QAppNodeType.PROCESS) { @@ -281,6 +293,16 @@ export default function App() component: , }); } + else if (app.type === QAppNodeType.REPORT) + { + const report = metaData.reports.get(app.name); + routeList.push({ + name: `${app.label}`, + key: app.name, + route: path, + component: , + }); + } } try diff --git a/src/qqq/components/ProcessLinkCard/index.tsx b/src/qqq/components/ProcessLinkCard/index.tsx index 3aa3cdc..2588ac0 100644 --- a/src/qqq/components/ProcessLinkCard/index.tsx +++ b/src/qqq/components/ProcessLinkCard/index.tsx @@ -29,6 +29,7 @@ import MDTypography from "qqq/components/Temporary/MDTypography"; interface Props { color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "light" | "dark"; + isReport?: boolean; title: string; percentage?: { color: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark" | "white"; @@ -41,7 +42,7 @@ interface Props } function ProcessLinkCard({ - color, title, percentage, icon, + color, isReport, title, percentage, icon, }: Props): JSX.Element { return ( @@ -81,10 +82,11 @@ function ProcessLinkCard({ > {percentage.amount} - Click here to run the process called - {" "} - {title} - . + { + isReport + ? `Click here to run the process called ${title}.` + : `Click here to access the ${title} report.` + } {percentage.label} @@ -94,6 +96,7 @@ function ProcessLinkCard({ ProcessLinkCard.defaultProps = { color: "info", + isReport: false, percentage: { color: "success", text: "", diff --git a/src/qqq/pages/app-home/index.tsx b/src/qqq/pages/app-home/index.tsx index d375ed3..827274d 100644 --- a/src/qqq/pages/app-home/index.tsx +++ b/src/qqq/pages/app-home/index.tsx @@ -22,6 +22,7 @@ import {QAppMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QApp import {QAppNodeType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAppNodeType"; import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance"; import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData"; +import {QReportMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QReportMetaData"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {Icon} from "@mui/material"; import Card from "@mui/material/Card"; @@ -53,6 +54,7 @@ function AppHome({app}: Props): JSX.Element const [qInstance, setQInstance] = useState(null as QInstance); const [tables, setTables] = useState([] as QTableMetaData[]); const [processes, setProcesses] = useState([] as QProcessMetaData[]); + const [reports, setReports] = useState([] as QReportMetaData[]); const [childApps, setChildApps] = useState([] as QAppMetaData[]); const [tableCounts, setTableCounts] = useState(new Map()); const [updatedTableCounts, setUpdatedTableCounts] = useState(new Date()); @@ -78,6 +80,7 @@ function AppHome({app}: Props): JSX.Element const newTables: QTableMetaData[] = []; const newProcesses: QProcessMetaData[] = []; + const newReports: QReportMetaData[] = []; const newChildApps: QAppMetaData[] = []; app.children.forEach((child) => @@ -91,6 +94,9 @@ function AppHome({app}: Props): JSX.Element case QAppNodeType.PROCESS: newProcesses.push(qInstance.processes.get(child.name)); break; + case QAppNodeType.REPORT: + newReports.push(qInstance.reports.get(child.name)); + break; case QAppNodeType.APP: newChildApps.push(qInstance.apps.get(child.name)); break; @@ -101,6 +107,7 @@ function AppHome({app}: Props): JSX.Element setTables(newTables); setProcesses(newProcesses); + setReports(newReports); setChildApps(newChildApps); const tableCounts = new Map(); @@ -231,7 +238,6 @@ function AppHome({app}: Props): JSX.Element { app.sections ? ( - {app.sections.map((section) => ( @@ -268,7 +274,42 @@ function AppHome({app}: Props): JSX.Element ) : null } { - section.processes && section.tables ? ( + section.processes && section.reports ? ( + + ) : null + } + { + section.reports ? ( + + Reports + + ) : null + } + { + section.reports ? ( + + { + section.reports.map((reportName) => + { + let report = app.childMap.get(reportName); + return ( + + + + + + ); + }) + } + + ) : null + } + { + section.reports && section.tables ? ( ) : null } diff --git a/src/qqq/pages/process-run/ReportRun.tsx b/src/qqq/pages/process-run/ReportRun.tsx new file mode 100644 index 0000000..b048fa9 --- /dev/null +++ b/src/qqq/pages/process-run/ReportRun.tsx @@ -0,0 +1,71 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2022. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance"; +import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData"; +import {QReportMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QReportMetaData"; +import React, {useEffect, useState} from "react"; +import ProcessRun from "qqq/pages/process-run/index"; +import QClient from "qqq/utils/QClient"; + +interface Props +{ + report?: QReportMetaData; +} + +function ReportRun({report}: Props): JSX.Element +{ + // const reportNameParam = useParams().reportName; + // const processName = process === null ? processNameParam : process.name; + const [metaData, setMetaData] = useState(null as QInstance); + + useEffect(() => + { + if(!metaData) + { + (async () => + { + const metaData = await QClient.getInstance().loadMetaData(); + setMetaData(metaData); + })(); + } + }); + + if(metaData) + { + console.log(`Report Process name is ${report.processName}`) + const process = metaData.processes.get(report.processName) + console.log(`Process is ${process.name}`) + const defaultProcessValues = {reportName: report.name} + return (); + } + else + { + // todo - loading? + return (
); + } +} + +ReportRun.defaultProps = { + process: null, +}; + +export default ReportRun; diff --git a/src/qqq/pages/process-run/index.tsx b/src/qqq/pages/process-run/index.tsx index e248e2a..8a3db4d 100644 --- a/src/qqq/pages/process-run/index.tsx +++ b/src/qqq/pages/process-run/index.tsx @@ -35,6 +35,7 @@ import {Button, Icon, CircularProgress, TablePagination} from "@mui/material"; import Box from "@mui/material/Box"; import Card from "@mui/material/Card"; import Grid from "@mui/material/Grid"; +import Link from "@mui/material/Link"; import Step from "@mui/material/Step"; import StepLabel from "@mui/material/StepLabel"; import Stepper from "@mui/material/Stepper"; @@ -42,7 +43,7 @@ import Typography from "@mui/material/Typography"; import {DataGridPro, GridColDef} from "@mui/x-data-grid-pro"; import FormData from "form-data"; import {Form, Formik} from "formik"; -import React, {Fragment, useEffect, useState} from "react"; +import React, {useEffect, useState} from "react"; import {useLocation, useParams, useNavigate} from "react-router-dom"; import * as Yup from "yup"; import BaseLayout from "qqq/components/BaseLayout"; @@ -61,13 +62,14 @@ import QProcessSummaryResults from "./components/QProcessSummaryResults"; interface Props { process?: QProcessMetaData; + defaultProcessValues?: any; } const INITIAL_RETRY_MILLIS = 1_500; const RETRY_MAX_MILLIS = 12_000; const BACKOFF_AMOUNT = 1.5; -function ProcessRun({process}: Props): JSX.Element +function ProcessRun({process, defaultProcessValues}: Props): JSX.Element { const processNameParam = useParams().processName; const processName = process === null ? processNameParam : process.name; @@ -339,6 +341,29 @@ function ProcessRun({process}: Props): JSX.Element
) } + { + component.type === QComponentType.DOWNLOAD_FORM && ( + + + + + Download + + + + + + download_for_offline + + {processValues.downloadFileName} + + + + + + + ) + } { component.type === QComponentType.VALIDATION_REVIEW_SCREEN && ( + { + let rs: QFieldMetaData[] = []; + + if(activeStep && activeStep.formFields) + { + for(let i = 0; i + fullFieldList.forEach((field) => { initialValues[field.name] = processValues[field.name]; }); @@ -492,7 +540,7 @@ function ProcessRun({process}: Props): JSX.Element if (doesStepHaveComponent(activeStep, QComponentType.BULK_EDIT_FORM)) { const newDisabledBulkEditFields: any = {}; - activeStep.formFields.forEach((field) => + fullFieldList.forEach((field) => { newDisabledBulkEditFields[field.name] = true; dynamicFormFields[field.name].isRequired = false; @@ -562,11 +610,12 @@ function ProcessRun({process}: Props): JSX.Element ///////////////////////////////////////////////////// useEffect(() => { - if (activeStep && activeStep.formFields) + if (activeStep && (activeStep.formFields || processValues.inputFieldList)) { + let fullFieldList = getFullFieldList(activeStep, processValues); const newDynamicFormFields: any = {}; const newFormValidations: any = {}; - activeStep.formFields.forEach((field) => + fullFieldList.forEach((field) => { const fieldName = field.name; const isDisabled = disabledBulkEditFields[fieldName]; @@ -738,22 +787,21 @@ function ProcessRun({process}: Props): JSX.Element (async () => { const urlSearchParams = new URLSearchParams(location.search); - let queryStringForInit = null; + let queryStringPairsForInit = []; if (urlSearchParams.get("recordIds")) { - queryStringForInit = `recordsParam=recordIds&recordIds=${urlSearchParams.get( - "recordIds", - )}`; + queryStringPairsForInit.push("recordsParam=recordIds"); + queryStringPairsForInit.push(`recordIds=${urlSearchParams.get("recordIds")}`); } else if (urlSearchParams.get("filterJSON")) { - queryStringForInit = `recordsParam=filterJSON&filterJSON=${urlSearchParams.get( - "filterJSON", - )}`; + queryStringPairsForInit.push("recordsParam=filterJSON"); + queryStringPairsForInit.push(`filterJSON=${urlSearchParams.get("filterJSON")}`); } // todo once saved filters exist //else if(urlSearchParams.get("filterId")) { - // queryStringForInit = `recordsParam=filterId&filterId=${urlSearchParams.get("filterId")}` + // queryStringPairsForInit.push("recordsParam=filterId"); + // queryStringPairsForInit.push(`filterId=${urlSearchParams.get("filterId")}`); // } try @@ -792,9 +840,17 @@ function ProcessRun({process}: Props): JSX.Element return; } + if(defaultProcessValues) + { + for(let key in defaultProcessValues) + { + queryStringPairsForInit.push(`${key}=${encodeURIComponent(defaultProcessValues[key])}`); + } + } + try { - const processResponse = await QClient.getInstance().processInit(processName, queryStringForInit); + const processResponse = await QClient.getInstance().processInit(processName, queryStringPairsForInit.join("&")); setProcessUUID(processResponse.processUUID); setLastProcessResponse(processResponse); } @@ -830,7 +886,8 @@ function ProcessRun({process}: Props): JSX.Element if (doesStepHaveComponent(activeStep, QComponentType.BULK_EDIT_FORM)) { const bulkEditEnabledFields: string[] = []; - activeStep.formFields.forEach((field) => + let fullFieldList = getFullFieldList(activeStep, processValues); + fullFieldList.forEach((field) => { if (!disabledBulkEditFields[field.name]) { @@ -904,7 +961,7 @@ function ProcessRun({process}: Props): JSX.Element - + + { + const process = metaData.reports.get(key); + if (process.tableName === tableName) + { + matchingReports.push(process); + } + }); + return matchingReports; + } + } export default QProcessUtils; diff --git a/src/setupProxy.js b/src/setupProxy.js index a129a43..d6d896c 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -36,4 +36,12 @@ module.exports = function (app) changeOrigin: true, }), ); + + app.use( + "/download/*", + createProxyMiddleware({ + target: "http://localhost:8000", + changeOrigin: true, + }), + ); };