mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-17 21:00:45 +00:00
Add QGoogleDriveFolderPicker
This commit is contained in:
@ -13,7 +13,7 @@
|
|||||||
"@fullcalendar/interaction": "5.10.0",
|
"@fullcalendar/interaction": "5.10.0",
|
||||||
"@fullcalendar/react": "5.10.0",
|
"@fullcalendar/react": "5.10.0",
|
||||||
"@fullcalendar/timegrid": "5.10.0",
|
"@fullcalendar/timegrid": "5.10.0",
|
||||||
"@kingsrook/qqq-frontend-core": "1.0.17",
|
"@kingsrook/qqq-frontend-core": "1.0.20",
|
||||||
"@mui/icons-material": "5.4.1",
|
"@mui/icons-material": "5.4.1",
|
||||||
"@mui/material": "5.4.1",
|
"@mui/material": "5.4.1",
|
||||||
"@mui/styled-engine": "5.4.1",
|
"@mui/styled-engine": "5.4.1",
|
||||||
@ -45,6 +45,7 @@
|
|||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
"react-flatpickr": "3.10.7",
|
"react-flatpickr": "3.10.7",
|
||||||
"react-github-btn": "1.2.1",
|
"react-github-btn": "1.2.1",
|
||||||
|
"react-google-drive-picker": "^1.2.0",
|
||||||
"react-html-parser": "2.0.2",
|
"react-html-parser": "2.0.2",
|
||||||
"react-images-viewer": "1.7.1",
|
"react-images-viewer": "1.7.1",
|
||||||
"react-quill": "1.3.5",
|
"react-quill": "1.3.5",
|
||||||
|
@ -84,8 +84,8 @@ function ProcessLinkCard({
|
|||||||
</MDTypography>
|
</MDTypography>
|
||||||
{
|
{
|
||||||
isReport
|
isReport
|
||||||
? `Click here to run the process called ${title}.`
|
? `Click here to access the ${title} report.`
|
||||||
: `Click here to access the ${title} report.`
|
: `Click here to run the process called ${title}.`
|
||||||
}
|
}
|
||||||
{percentage.label}
|
{percentage.label}
|
||||||
</MDTypography>
|
</MDTypography>
|
||||||
|
@ -87,6 +87,11 @@ function QDynamicForm(props: Props): JSX.Element
|
|||||||
values[fieldName] = "";
|
values[fieldName] = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field.omitFromQDynamicForm)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (field.type === "file")
|
if (field.type === "file")
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
@ -95,7 +100,7 @@ function QDynamicForm(props: Props): JSX.Element
|
|||||||
|
|
||||||
<Box display="flex" alignItems="center">
|
<Box display="flex" alignItems="center">
|
||||||
<Button variant="outlined" component="label">
|
<Button variant="outlined" component="label">
|
||||||
<span style={{color: "#606060"}}>Choose file to upload</span>
|
<span style={{color: colors.lightBlue[500]}}>Choose file to upload</span>
|
||||||
<input
|
<input
|
||||||
id={fieldName}
|
id={fieldName}
|
||||||
name={fieldName}
|
name={fieldName}
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {colors} from "@mui/material"
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import Grid from "@mui/material/Grid";
|
||||||
|
import {useFormikContext} from "formik";
|
||||||
|
import React, {useEffect, useState} from "react";
|
||||||
|
import useDrivePicker from "react-google-drive-picker";
|
||||||
|
import MDBox from "qqq/components/Temporary/MDBox";
|
||||||
|
|
||||||
|
export function QGoogleDriveFolderPicker(): JSX.Element
|
||||||
|
{
|
||||||
|
const clientId = process.env.REACT_APP_GOOGLE_APP_CLIENT_ID;
|
||||||
|
const appApiKey = process.env.REACT_APP_GOOGLE_APP_API_KEY;
|
||||||
|
|
||||||
|
const [ selectedGoogleFolderName, setSelectedGoogleFolderName ] = useState(null as string);
|
||||||
|
const [ selectedGoogleFolderId, setSelectedGoogleFolderId ] = useState(null as string);
|
||||||
|
const [ googleToken, setGoogleToken ] = useState(null as string); // maybe get from cookie/local-storage
|
||||||
|
|
||||||
|
const [ openPicker, authResponse ] = useDrivePicker();
|
||||||
|
|
||||||
|
const formikProps = useFormikContext();
|
||||||
|
|
||||||
|
const handleOpenPicker = (token: string) =>
|
||||||
|
{
|
||||||
|
openPicker({
|
||||||
|
clientId: clientId,
|
||||||
|
developerKey: appApiKey,
|
||||||
|
viewId: "FOLDERS",
|
||||||
|
token: token, // pass oauth token in case you already have one
|
||||||
|
showUploadView: false,
|
||||||
|
showUploadFolders: false,
|
||||||
|
supportDrives: true,
|
||||||
|
multiselect: false,
|
||||||
|
setSelectFolderEnabled: true,
|
||||||
|
setIncludeFolders: true,
|
||||||
|
callbackFunction: (data) =>
|
||||||
|
{
|
||||||
|
if (data.action === "cancel")
|
||||||
|
{
|
||||||
|
console.log("User clicked cancel/close button");
|
||||||
|
setSelectedGoogleFolderId(null);
|
||||||
|
setSelectedGoogleFolderName(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log(data);
|
||||||
|
setSelectedGoogleFolderId(data.docs[0].id);
|
||||||
|
setSelectedGoogleFolderName(data.docs[0].name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if(authResponse && authResponse.access_token && authResponse.access_token !== googleToken)
|
||||||
|
{
|
||||||
|
setGoogleToken(authResponse.access_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
formikProps.setFieldValue("googleDriveAccessToken", authResponse?.access_token);
|
||||||
|
formikProps.setFieldValue("googleDriveFolderId", selectedGoogleFolderId);
|
||||||
|
formikProps.setFieldValue("googleDriveFolderName", selectedGoogleFolderName);
|
||||||
|
}, [selectedGoogleFolderId, selectedGoogleFolderName])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<MDBox mb={1.5}>
|
||||||
|
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Button variant="outlined" onClick={() => handleOpenPicker(googleToken)}>
|
||||||
|
<span style={{color: colors.lightBlue[500]}}>Select Google Drive Folder</span>
|
||||||
|
</Button>
|
||||||
|
<Box ml={1} fontSize={"1rem"}>
|
||||||
|
{selectedGoogleFolderName}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/*
|
||||||
|
<MDBox mt={0.75}>
|
||||||
|
<MDTypography component="div" variant="caption" color="error" fontWeight="regular">
|
||||||
|
{errors[fieldName] && <span>You must select a file to proceed</span>}
|
||||||
|
</MDTypography>
|
||||||
|
</MDBox>
|
||||||
|
*/}
|
||||||
|
</MDBox>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
@ -54,6 +54,7 @@ import MDBox from "qqq/components/Temporary/MDBox";
|
|||||||
import MDButton from "qqq/components/Temporary/MDButton";
|
import MDButton from "qqq/components/Temporary/MDButton";
|
||||||
import MDProgress from "qqq/components/Temporary/MDProgress";
|
import MDProgress from "qqq/components/Temporary/MDProgress";
|
||||||
import MDTypography from "qqq/components/Temporary/MDTypography";
|
import MDTypography from "qqq/components/Temporary/MDTypography";
|
||||||
|
import {QGoogleDriveFolderPicker} from "qqq/pages/process-run/components/QGoogleDriveFolderPicker";
|
||||||
import QValidationReview from "qqq/pages/process-run/components/QValidationReview";
|
import QValidationReview from "qqq/pages/process-run/components/QValidationReview";
|
||||||
import QClient from "qqq/utils/QClient";
|
import QClient from "qqq/utils/QClient";
|
||||||
import QValueUtils from "qqq/utils/QValueUtils";
|
import QValueUtils from "qqq/utils/QValueUtils";
|
||||||
@ -393,6 +394,11 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
<QProcessSummaryResults qInstance={qInstance} process={processMetaData} table={tableMetaData} processValues={processValues} step={step} />
|
<QProcessSummaryResults qInstance={qInstance} process={processMetaData} table={tableMetaData} processValues={processValues} step={step} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
component.type === QComponentType.GOOGLE_DRIVE_SELECT_FOLDER && (
|
||||||
|
<QGoogleDriveFolderPicker />
|
||||||
|
)
|
||||||
|
}
|
||||||
{
|
{
|
||||||
component.type === QComponentType.RECORD_LIST && step.recordListFields && recordConfig.columns && (
|
component.type === QComponentType.RECORD_LIST && step.recordListFields && recordConfig.columns && (
|
||||||
<div>
|
<div>
|
||||||
@ -510,6 +516,7 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
if (newIndex === null)
|
if (newIndex === null)
|
||||||
{
|
{
|
||||||
setProcessError(`Unknown process step ${newStep}.`);
|
setProcessError(`Unknown process step ${newStep}.`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
setActiveStepIndex(newIndex);
|
setActiveStepIndex(newIndex);
|
||||||
setOverrideOnLastStep(null);
|
setOverrideOnLastStep(null);
|
||||||
@ -520,15 +527,20 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
setActiveStep(activeStep);
|
setActiveStep(activeStep);
|
||||||
setFormId(activeStep.name);
|
setFormId(activeStep.name);
|
||||||
|
|
||||||
|
let dynamicFormFields: any = {};
|
||||||
|
let formValidations: any = {};
|
||||||
|
let initialValues: any = {};
|
||||||
|
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
// if this step has form fields, set up the form //
|
// if this step has form fields, set up the form //
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
if (activeStep.formFields || processValues.inputFieldList)
|
if (activeStep.formFields || processValues.inputFieldList)
|
||||||
{
|
{
|
||||||
let fullFieldList = getFullFieldList(activeStep, processValues);
|
let fullFieldList = getFullFieldList(activeStep, processValues);
|
||||||
const {dynamicFormFields, formValidations} = DynamicFormUtils.getFormData(fullFieldList);
|
const formData = DynamicFormUtils.getFormData(fullFieldList);
|
||||||
|
dynamicFormFields = formData.dynamicFormFields;
|
||||||
|
formValidations = formData.formValidations;
|
||||||
|
|
||||||
const initialValues: any = {};
|
|
||||||
fullFieldList.forEach((field) =>
|
fullFieldList.forEach((field) =>
|
||||||
{
|
{
|
||||||
initialValues[field.name] = processValues[field.name];
|
initialValues[field.name] = processValues[field.name];
|
||||||
@ -548,27 +560,36 @@ function ProcessRun({process, defaultProcessValues}: Props): JSX.Element
|
|||||||
});
|
});
|
||||||
setDisabledBulkEditFields(newDisabledBulkEditFields);
|
setDisabledBulkEditFields(newDisabledBulkEditFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFormFields(dynamicFormFields);
|
|
||||||
setInitialValues(initialValues);
|
|
||||||
setValidationScheme(Yup.object().shape(formValidations));
|
|
||||||
setValidationFunction(null);
|
|
||||||
}
|
}
|
||||||
else if (doesStepHaveComponent(activeStep, QComponentType.VALIDATION_REVIEW_SCREEN))
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// define an inner function here, for adding more fields to the form, if any components have form fields built into them //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const addField = (fieldName: string, dynamicFormValue: any, initialValue: any, validation: any) =>
|
||||||
{
|
{
|
||||||
////////////////////////////////////////
|
dynamicFormFields[fieldName] = dynamicFormValue;
|
||||||
// this component requires this field //
|
initialValues[fieldName] = initialValue;
|
||||||
////////////////////////////////////////
|
formValidations[fieldName] = validation;
|
||||||
const dynamicFormFields: any = {};
|
}
|
||||||
dynamicFormFields.doFullValidation = {type: "radio"};
|
|
||||||
|
|
||||||
const initialValues: any = {};
|
if (doesStepHaveComponent(activeStep, QComponentType.VALIDATION_REVIEW_SCREEN))
|
||||||
initialValues.doFullValidation = "true";
|
{
|
||||||
|
addField("doFullValidation", {type: "radio"}, "true", null);
|
||||||
setOverrideOnLastStep(false);
|
setOverrideOnLastStep(false);
|
||||||
|
}
|
||||||
|
|
||||||
const formValidations: any = {};
|
if (doesStepHaveComponent(activeStep, QComponentType.GOOGLE_DRIVE_SELECT_FOLDER))
|
||||||
formValidations.doFullValidation = null;
|
{
|
||||||
|
addField("googleDriveAccessToken", {type: "hidden", omitFromQDynamicForm: true}, null, null);
|
||||||
|
addField("googleDriveFolderId", {type: "hidden", omitFromQDynamicForm: true}, null, null);
|
||||||
|
addField("googleDriveFolderName", {type: "hidden", omitFromQDynamicForm: true}, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Object.keys(dynamicFormFields).length > 0)
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// if there are form fields, set them up //
|
||||||
|
///////////////////////////////////////////
|
||||||
setFormFields(dynamicFormFields);
|
setFormFields(dynamicFormFields);
|
||||||
setInitialValues(initialValues);
|
setInitialValues(initialValues);
|
||||||
setValidationScheme(Yup.object().shape(formValidations));
|
setValidationScheme(Yup.object().shape(formValidations));
|
||||||
|
Reference in New Issue
Block a user