added create new instance page and moved model run to a component w/ burnettk cullerton
This commit is contained in:
parent
cb8e110f2c
commit
919150b73b
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
);
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import ProcessModelListTiles from '../components/ProcessModelListTiles';
|
||||||
|
|
||||||
|
export default function CreateNewInstance() {
|
||||||
|
return (
|
||||||
|
<ProcessModelListTiles
|
||||||
|
headerElement={<h1>Process models available to you</h1>}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue