added create new instance page and moved model run to a component w/ burnettk cullerton

This commit is contained in:
jasquat 2022-11-18 16:40:49 -05:00
parent cb8e110f2c
commit 919150b73b
9 changed files with 216 additions and 35 deletions

View File

@ -60,10 +60,10 @@ export default function ProcessGroupListTiles({
<div className="tile-process-group-display-name"> <div className="tile-process-group-display-name">
{row.display_name} {row.display_name}
</div> </div>
<p className="tile-process-group-description"> <p className="tile-description">
{truncateString(row.description || '', 25)} {truncateString(row.description || '', 25)}
</p> </p>
<p className="tile-process-group-children-count"> <p className="tile-process-group-children-count tile-pin-bottom">
Total Sub Items: {processGroupDirectChildrenCount(row)} Total Sub Items: {processGroupDirectChildrenCount(row)}
</p> </p>
</div> </div>

View File

@ -0,0 +1,64 @@
import { useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Button,
// @ts-ignore
} from '@carbon/react';
import { ProcessModel } from '../interfaces';
import HttpService from '../services/HttpService';
import ErrorContext from '../contexts/ErrorContext';
import { modifyProcessModelPath } from '../helpers';
type OwnProps = {
processModel: ProcessModel;
onSuccessCallback: Function;
className?: string;
};
export default function ProcessInstanceRun({
processModel,
onSuccessCallback,
className,
}: OwnProps) {
const navigate = useNavigate();
const setErrorMessage = (useContext as any)(ErrorContext)[1];
const modifiedProcessModelId = modifyProcessModelPath(processModel.id);
const onProcessInstanceRun = (processInstance: any) => {
// FIXME: ensure that the task is actually for the current user as well
const processInstanceId = (processInstance as any).id;
const nextTask = (processInstance as any).next_task;
if (nextTask && nextTask.state === 'READY') {
navigate(`/tasks/${processInstanceId}/${nextTask.id}`);
}
onSuccessCallback(processInstance);
};
const processModelRun = (processInstance: any) => {
setErrorMessage(null);
HttpService.makeCallToBackend({
path: `/process-instances/${processInstance.id}/run`,
successCallback: onProcessInstanceRun,
failureCallback: setErrorMessage,
httpMethod: 'POST',
});
};
const processInstanceCreateAndRun = () => {
HttpService.makeCallToBackend({
path: `/process-models/${modifiedProcessModelId}/process-instances`,
successCallback: processModelRun,
httpMethod: 'POST',
});
};
return (
<Button
onClick={processInstanceCreateAndRun}
variant="primary"
className={className}
>
Run
</Button>
);
}

View File

@ -42,7 +42,7 @@ export default function ProcessModelForm({
const handleFormSubmission = (event: any) => { const handleFormSubmission = (event: any) => {
event.preventDefault(); event.preventDefault();
let hasErrors = false; let hasErrors = false;
if (!hasValidIdentifier(processModel.id)) { if (mode === 'new' && !hasValidIdentifier(processModel.id)) {
setIdentifierInvalid(true); setIdentifierInvalid(true);
hasErrors = true; hasErrors = true;
} }

View File

@ -0,0 +1,105 @@
import { ReactElement, useEffect, useState } from 'react';
import { Link, useSearchParams } from 'react-router-dom';
import {
Tile,
// @ts-ignore
} from '@carbon/react';
import HttpService from '../services/HttpService';
import { ProcessModel, ProcessInstance } from '../interfaces';
import { modifyProcessModelPath, truncateString } from '../helpers';
import ProcessInstanceRun from './ProcessInstanceRun';
type OwnProps = {
headerElement?: ReactElement;
};
export default function ProcessModelListTiles({ headerElement }: OwnProps) {
const [searchParams] = useSearchParams();
const [processModels, setProcessModels] = useState<ProcessModel[] | null>(
null
);
const [processInstance, setProcessInstance] =
useState<ProcessInstance | null>(null);
useEffect(() => {
const setProcessModelsFromResult = (result: any) => {
setProcessModels(result.results);
};
// only allow 10 for now until we get the backend only returnin certain models for user execution
const queryParams = '?per_page=10';
HttpService.makeCallToBackend({
path: `/process-models${queryParams}`,
successCallback: setProcessModelsFromResult,
});
}, [searchParams]);
const processInstanceRunResultTag = () => {
if (processInstance) {
return (
<div className="alert alert-success" role="alert">
<p>
Process Instance {processInstance.id} kicked off (
<Link
to={`/admin/process-models/${modifyProcessModelPath(
processInstance.process_model_identifier
)}/process-instances/${processInstance.id}`}
data-qa="process-instance-show-link"
>
view
</Link>
).
</p>
</div>
);
}
return null;
};
const processModelsDisplayArea = () => {
let displayText = null;
if (processModels && processModels.length > 0) {
displayText = (processModels || []).map((row: ProcessModel) => {
return (
<Tile
id="tile-1"
className="tile-process-group"
href={`/admin/process-models/${modifyProcessModelPath(row.id)}`}
>
<div className="tile-process-group-content-container">
<div className="tile-title-top">{row.display_name}</div>
<p className="tile-description">
{truncateString(row.description || '', 25)}
</p>
<ProcessInstanceRun
processModel={row}
onSuccessCallback={setProcessInstance}
className="tile-pin-bottom"
/>
</div>
</Tile>
);
});
} else {
displayText = <p>No Models To Display</p>;
}
return displayText;
};
const processModelArea = () => {
if (processModels && processModels.length > 0) {
return (
<>
{headerElement}
{processInstanceRunResultTag()}
{processModelsDisplayArea()}
</>
);
}
return null;
};
if (processModels) {
return <>{processModelArea()}</>;
}
return null;
}

View File

@ -215,7 +215,15 @@ in on this with the react-jsonschema-form repo. This is just a patch fix to allo
order: 0; order: 0;
} }
.tile-process-group-description { .tile-title-top {
margin-bottom: 2em;
font-size: 20px;
line-height: 28px;
color: #161616;
order: 0;
}
.tile-description {
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 20px;
letter-spacing: 0.16px; letter-spacing: 0.16px;
@ -229,6 +237,9 @@ in on this with the react-jsonschema-form repo. This is just a patch fix to allo
letter-spacing: 0.16px; letter-spacing: 0.16px;
color: #161616; color: #161616;
order: 1; order: 1;
}
.tile-pin-bottom {
position: absolute; position: absolute;
bottom: 1em; bottom: 1em;
} }

View File

@ -36,6 +36,11 @@ export interface ProcessFile {
file_contents?: string; file_contents?: string;
} }
export interface ProcessInstance {
id: number;
process_model_identifier: string;
}
export interface ProcessModel { export interface ProcessModel {
id: string; id: string;
description: string; description: string;

View File

@ -0,0 +1,9 @@
import ProcessModelListTiles from '../components/ProcessModelListTiles';
export default function CreateNewInstance() {
return (
<ProcessModelListTiles
headerElement={<h1>Process models available to you</h1>}
/>
);
}

View File

@ -7,6 +7,7 @@ import ErrorContext from '../contexts/ErrorContext';
import MyTasks from './MyTasks'; import MyTasks from './MyTasks';
import GroupedTasks from './GroupedTasks'; import GroupedTasks from './GroupedTasks';
import CompletedInstances from './CompletedInstances'; import CompletedInstances from './CompletedInstances';
import CreateNewInstance from './CreateNewInstance';
export default function HomePageRoutes() { export default function HomePageRoutes() {
const location = useLocation(); const location = useLocation();
@ -21,6 +22,8 @@ export default function HomePageRoutes() {
newSelectedTabIndex = 1; newSelectedTabIndex = 1;
} else if (location.pathname.match(/^\/tasks\/completed-instances\b/)) { } else if (location.pathname.match(/^\/tasks\/completed-instances\b/)) {
newSelectedTabIndex = 2; newSelectedTabIndex = 2;
} else if (location.pathname.match(/^\/tasks\/create-new-instance\b/)) {
newSelectedTabIndex = 3;
} }
setSelectedTabIndex(newSelectedTabIndex); setSelectedTabIndex(newSelectedTabIndex);
}, [location, setErrorMessage]); }, [location, setErrorMessage]);
@ -34,6 +37,9 @@ export default function HomePageRoutes() {
<Tab onClick={() => navigate('/tasks/completed-instances')}> <Tab onClick={() => navigate('/tasks/completed-instances')}>
Completed Instances Completed Instances
</Tab> </Tab>
<Tab onClick={() => navigate('/tasks/create-new-instance')}>
Create New Instance +
</Tab>
</TabList> </TabList>
</Tabs> </Tabs>
<br /> <br />
@ -43,6 +49,7 @@ export default function HomePageRoutes() {
<Route path=":process_instance_id/:task_id" element={<TaskShow />} /> <Route path=":process_instance_id/:task_id" element={<TaskShow />} />
<Route path="grouped" element={<GroupedTasks />} /> <Route path="grouped" element={<GroupedTasks />} />
<Route path="completed-instances" element={<CompletedInstances />} /> <Route path="completed-instances" element={<CompletedInstances />} />
<Route path="create-new-instance" element={<CreateNewInstance />} />
</Routes> </Routes>
</> </>
); );

View File

@ -38,6 +38,7 @@ import {
import { import {
PermissionsToCheck, PermissionsToCheck,
ProcessFile, ProcessFile,
ProcessInstance,
ProcessModel, ProcessModel,
RecentProcessModel, RecentProcessModel,
} from '../interfaces'; } from '../interfaces';
@ -45,6 +46,7 @@ import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
import ProcessInstanceListTable from '../components/ProcessInstanceListTable'; import ProcessInstanceListTable from '../components/ProcessInstanceListTable';
import { usePermissionFetcher } from '../hooks/PermissionService'; import { usePermissionFetcher } from '../hooks/PermissionService';
import { useUriListForPermissions } from '../hooks/UriListForPermissions'; import { useUriListForPermissions } from '../hooks/UriListForPermissions';
import ProcessInstanceRun from '../components/ProcessInstanceRun';
const storeRecentProcessModelInLocalStorage = ( const storeRecentProcessModelInLocalStorage = (
processModelForStorage: ProcessModel processModelForStorage: ProcessModel
@ -100,7 +102,8 @@ export default function ProcessModelShow() {
const setErrorMessage = (useContext as any)(ErrorContext)[1]; const setErrorMessage = (useContext as any)(ErrorContext)[1];
const [processModel, setProcessModel] = useState<ProcessModel | null>(null); const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
const [processInstanceResult, setProcessInstanceResult] = useState(null); const [processInstance, setProcessInstance] =
useState<ProcessInstance | null>(null);
const [reloadModel, setReloadModel] = useState<boolean>(false); const [reloadModel, setReloadModel] = useState<boolean>(false);
const [filesToUpload, setFilesToUpload] = useState<any>(null); const [filesToUpload, setFilesToUpload] = useState<any>(null);
const [showFileUploadModal, setShowFileUploadModal] = const [showFileUploadModal, setShowFileUploadModal] =
@ -132,38 +135,14 @@ export default function ProcessModelShow() {
}); });
}, [reloadModel, modifiedProcessModelId]); }, [reloadModel, modifiedProcessModelId]);
const processModelRun = (processInstance: any) => {
setErrorMessage(null);
HttpService.makeCallToBackend({
path: `/process-instances/${processInstance.id}/run`,
successCallback: setProcessInstanceResult,
failureCallback: setErrorMessage,
httpMethod: 'POST',
});
};
const processInstanceCreateAndRun = () => {
HttpService.makeCallToBackend({
path: `/process-models/${modifiedProcessModelId}/process-instances`,
successCallback: processModelRun,
httpMethod: 'POST',
});
};
const processInstanceRunResultTag = () => { const processInstanceRunResultTag = () => {
if (processModel && processInstanceResult) { if (processInstance) {
// FIXME: ensure that the task is actually for the current user as well
const processInstanceId = (processInstanceResult as any).id;
const nextTask = (processInstanceResult as any).next_task;
if (nextTask && nextTask.state === 'READY') {
navigate(`/tasks/${processInstanceId}/${nextTask.id}`);
}
return ( return (
<div className="alert alert-success" role="alert"> <div className="alert alert-success" role="alert">
<p> <p>
Process Instance {processInstanceId} kicked off ( Process Instance {processInstance.id} kicked off (
<Link <Link
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${processInstanceId}`} to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${processInstance.id}`}
data-qa="process-instance-show-link" data-qa="process-instance-show-link"
> >
view view
@ -572,9 +551,10 @@ export default function ProcessModelShow() {
a={targetUris.processInstanceActionPath} a={targetUris.processInstanceActionPath}
ability={ability} ability={ability}
> >
<Button onClick={processInstanceCreateAndRun} variant="primary"> <ProcessInstanceRun
Run processModel={processModel}
</Button> onSuccessCallback={setProcessInstance}
/>
</Can> </Can>
<Can I="PUT" a={targetUris.processModelShowPath} ability={ability}> <Can I="PUT" a={targetUris.processModelShowPath} ability={ability}>
<Button <Button