diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py index 359facec2..b90968cab 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -247,7 +247,7 @@ def process_model_update( process_group_id: str, process_model_id: str, body: Dict[str, Union[str, bool, int]] ) -> Any: """Process_model_update.""" - body_include_list = ["display_name", "primary_file_name", "primary_process_id"] + body_include_list = ["display_name", "primary_file_name", "primary_process_id", "description"] body_filtered = { include_item: body[include_item] for include_item in body_include_list diff --git a/spiffworkflow-frontend/src/components/ProcessGroupForm.tsx b/spiffworkflow-frontend/src/components/ProcessGroupForm.tsx index 128a13c0c..7f83923fc 100644 --- a/spiffworkflow-frontend/src/components/ProcessGroupForm.tsx +++ b/spiffworkflow-frontend/src/components/ProcessGroupForm.tsx @@ -95,7 +95,7 @@ export default function ProcessGroupForm({ const onDisplayNameChanged = (newDisplayName: any) => { setDisplayNameInvalid(false); const updateDict = { display_name: newDisplayName }; - if (!idHasBeenUpdatedByUser) { + if (!idHasBeenUpdatedByUser && mode === 'new') { Object.assign(updateDict, { id: slugifyString(newDisplayName) }); } updateProcessGroup(updateDict); diff --git a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx new file mode 100644 index 000000000..2c7f67c7e --- /dev/null +++ b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx @@ -0,0 +1,188 @@ +import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +// @ts-ignore +import { Button, ButtonSet, Form, Stack, TextInput } from '@carbon/react'; +import { slugifyString } from '../helpers'; +import HttpService from '../services/HttpService'; +import { ProcessModel } from '../interfaces'; +import ButtonWithConfirmation from './ButtonWithConfirmation'; + +type OwnProps = { + mode: string; + processModel: ProcessModel; + setProcessModel: (..._args: any[]) => any; +}; + +export default function ProcessModelForm({ + mode, + processModel, + setProcessModel, +}: OwnProps) { + const [identifierInvalid, setIdentifierInvalid] = useState(false); + const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] = + useState(false); + const [displayNameInvalid, setDisplayNameInvalid] = useState(false); + const navigate = useNavigate(); + + const navigateToProcessModel = (_result: any) => { + if (processModel) { + navigate( + `/admin/process-models/${processModel.process_group_id}/${processModel.id}` + ); + } + }; + + const navigateToProcessModels = (_result: any) => { + navigate(`/admin/process-models/${processModel.process_group_id}`); + }; + + const hasValidIdentifier = (identifierToCheck: string) => { + return identifierToCheck.match(/^[a-z0-9][0-9a-z-]+[a-z0-9]$/); + }; + + const deleteProcessModel = () => { + HttpService.makeCallToBackend({ + path: `/process-models/${processModel.process_group_id}/${processModel.id}`, + successCallback: navigateToProcessModels, + httpMethod: 'DELETE', + }); + }; + + const handleFormSubmission = (event: any) => { + event.preventDefault(); + let hasErrors = false; + if (!hasValidIdentifier(processModel.id)) { + setIdentifierInvalid(true); + hasErrors = true; + } + if (processModel.display_name === '') { + setDisplayNameInvalid(true); + hasErrors = true; + } + if (hasErrors) { + return; + } + let path = `/process-models`; + if (mode === 'edit') { + path = `/process-models/${processModel.process_group_id}/${processModel.id}`; + } + let httpMethod = 'POST'; + if (mode === 'edit') { + httpMethod = 'PUT'; + } + const postBody = { + display_name: processModel.display_name, + description: processModel.description, + }; + if (mode === 'new') { + Object.assign(postBody, { + id: processModel.id, + process_group_id: processModel.process_group_id, + }); + } + console.log('postBody', postBody); + HttpService.makeCallToBackend({ + path, + successCallback: navigateToProcessModel, + httpMethod, + postBody, + }); + }; + + const updateProcessModel = (newValues: any) => { + const processModelToCopy = { + ...processModel, + }; + Object.assign(processModelToCopy, newValues); + setProcessModel(processModelToCopy); + }; + + const onDisplayNameChanged = (newDisplayName: any) => { + setDisplayNameInvalid(false); + const updateDict = { display_name: newDisplayName }; + if (!idHasBeenUpdatedByUser && mode === 'new') { + Object.assign(updateDict, { id: slugifyString(newDisplayName) }); + } + updateProcessModel(updateDict); + }; + + const formElements = () => { + const textInputs = [ + { + onDisplayNameChanged(event.target.value); + }} + onBlur={(event: any) => console.log('event', event)} + />, + ]; + + if (mode === 'new') { + textInputs.push( + { + updateProcessModel({ id: event.target.value }); + // was invalid, and now valid + if (identifierInvalid && hasValidIdentifier(event.target.value)) { + setIdentifierInvalid(false); + } + setIdHasBeenUpdatedByUser(true); + }} + /> + ); + } + + textInputs.push( + + updateProcessModel({ description: event.target.value }) + } + /> + ); + + return textInputs; + }; + + const formButtons = () => { + const buttons = [ + , + ]; + if (mode === 'edit') { + buttons.push( + + ); + } + return {buttons}; + }; + console.log('processModel.process_group_id', processModel.process_group_id); + return ( +
+ + {formElements()} + {formButtons()} + +
+ ); +} diff --git a/spiffworkflow-frontend/src/routes/ProcessModelEdit.tsx b/spiffworkflow-frontend/src/routes/ProcessModelEdit.tsx index 3f3dfb780..e07f63074 100644 --- a/spiffworkflow-frontend/src/routes/ProcessModelEdit.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessModelEdit.tsx @@ -1,98 +1,32 @@ -import { useState, useEffect, useContext } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; +import { useState, useEffect } from 'react'; +import { useParams } from 'react-router-dom'; // @ts-ignore -import { Button, Stack } from '@carbon/react'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import HttpService from '../services/HttpService'; -import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; -import ErrorContext from '../contexts/ErrorContext'; +import ProcessModelForm from '../components/ProcessModelForm'; export default function ProcessModelEdit() { - const [displayName, setDisplayName] = useState(''); const params = useParams(); - const navigate = useNavigate(); const [processModel, setProcessModel] = useState(null); - const setErrorMessage = (useContext as any)(ErrorContext)[1]; - const processModelPath = `process-models/${params.process_group_id}/${params.process_model_id}`; useEffect(() => { - const processResult = (result: any) => { - setProcessModel(result); - setDisplayName(result.display_name); - }; HttpService.makeCallToBackend({ path: `/${processModelPath}`, - successCallback: processResult, + successCallback: setProcessModel, }); }, [processModelPath]); - const navigateToProcessModel = (_result: any) => { - navigate(`/admin/${processModelPath}`); - }; - - const navigateToProcessModels = (_result: any) => { - navigate(`/admin/process-groups/${params.process_group_id}`); - }; - - const updateProcessModel = (event: any) => { - const processModelToUse = processModel as any; - event.preventDefault(); - const processModelToPass = Object.assign(processModelToUse, { - display_name: displayName, - }); - HttpService.makeCallToBackend({ - path: `/${processModelPath}`, - successCallback: navigateToProcessModel, - httpMethod: 'PUT', - postBody: processModelToPass, - }); - }; - - // share with or delete from ProcessModelEditDiagram - const deleteProcessModel = () => { - setErrorMessage(null); - const processModelToUse = processModel as any; - const processModelShowPath = `/process-models/${processModelToUse.process_group_id}/${processModelToUse.id}`; - HttpService.makeCallToBackend({ - path: `${processModelShowPath}`, - successCallback: navigateToProcessModels, - httpMethod: 'DELETE', - failureCallback: setErrorMessage, - }); - }; - - const onDisplayNameChanged = (newDisplayName: any) => { - setDisplayName(newDisplayName); - }; - if (processModel) { return ( <> - -

Edit Process Group: {(processModel as any).id}

-
- - onDisplayNameChanged(e.target.value)} - /> -
-
- - - - - -
+ +

Edit Process Model: {(processModel as any).id}

+ ); } diff --git a/spiffworkflow-frontend/src/routes/ProcessModelNew.tsx b/spiffworkflow-frontend/src/routes/ProcessModelNew.tsx index fdcc784df..d0d55942d 100644 --- a/spiffworkflow-frontend/src/routes/ProcessModelNew.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessModelNew.tsx @@ -1,75 +1,30 @@ import { useState } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; -import Button from 'react-bootstrap/Button'; -import Form from 'react-bootstrap/Form'; +import { useParams } from 'react-router-dom'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; -import { slugifyString } from '../helpers'; -import HttpService from '../services/HttpService'; +import { ProcessModel } from '../interfaces'; +import ProcessModelForm from '../components/ProcessModelForm'; export default function ProcessModelNew() { const params = useParams(); - const [identifier, setIdentifier] = useState(''); - const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] = useState(false); - const [displayName, setDisplayName] = useState(''); - const navigate = useNavigate(); - - const navigateToNewProcessModel = (_result: any) => { - navigate(`/admin/process-models/${params.process_group_id}/${identifier}`); - }; - - const addProcessModel = (event: any) => { - event.preventDefault(); - HttpService.makeCallToBackend({ - path: `/process-models`, - successCallback: navigateToNewProcessModel, - httpMethod: 'POST', - postBody: { - id: identifier, - display_name: displayName, - description: displayName, - process_group_id: params.process_group_id, - }, - }); - }; - - const onDisplayNameChanged = (newDisplayName: any) => { - setDisplayName(newDisplayName); - if (!idHasBeenUpdatedByUser) { - setIdentifier(slugifyString(newDisplayName)); - } - }; + const [processModel, setProcessModel] = useState({ + id: '', + display_name: '', + description: '', + process_group_id: params.process_group_id || '', + primary_file_name: '', + files: [], + }); return ( <>

Add Process Model

-
- - Display Name: - onDisplayNameChanged(e.target.value)} - /> - - - ID: - { - setIdentifier(e.target.value); - setIdHasBeenUpdatedByUser(true); - }} - /> - - -
+ ); }