ProcessInterstitial is now a component, and a page. The component is included into both the Interstitial PAge and the Process Instance Show page.

Fixed routes for interstitial to align with those of the TaskShow page (variants are now accepted and passed through)

Removed the View button completely.
This commit is contained in:
danfunk 2023-05-24 15:24:33 -04:00
parent 3fcc4fd1a6
commit 0ebab2884b
9 changed files with 120 additions and 108 deletions

View File

@ -10,7 +10,6 @@ import HomePageRoutes from './routes/HomePageRoutes';
import About from './routes/About';
import ErrorBoundary from './components/ErrorBoundary';
import AdminRoutes from './routes/AdminRoutes';
import ProcessRoutes from './routes/ProcessRoutes';
import { AbilityContext } from './contexts/Can';
import UserService from './services/UserService';
@ -41,7 +40,6 @@ export default function App() {
<Route path="/*" element={<HomePageRoutes />} />
<Route path="/about" element={<About />} />
<Route path="/tasks/*" element={<HomePageRoutes />} />
<Route path="/process/*" element={<ProcessRoutes />} />
<Route path="/admin/*" element={<AdminRoutes />} />
</Routes>
</ErrorBoundary>

View File

@ -1590,9 +1590,7 @@ export default function ProcessInstanceListTable({
});
if (showActionsColumn) {
let buttonElement = null;
const interstitialUrl = `/process/${modifyProcessIdentifierForPathParam(
processInstance.process_model_identifier
)}/${processInstance.id}/interstitial`;
const taskShowUrl = `/tasks/${processInstance.id}/${processInstance.task_id}`;
const regex = new RegExp(`\\b(${preferredUsername}|${userEmail})\\b`);
let hasAccessToCompleteTask = false;
if (
@ -1601,21 +1599,19 @@ export default function ProcessInstanceListTable({
) {
hasAccessToCompleteTask = true;
}
let buttonText = 'View';
buttonElement = null;
if (hasAccessToCompleteTask && processInstance.task_id) {
buttonText = 'Go';
buttonElement = (
<Button
kind="secondary"
href={taskShowUrl}
style={{ width: '60px' }}
>
Go
</Button>
);
}
buttonElement = (
<Button
kind="secondary"
href={interstitialUrl}
style={{ width: '60px' }}
>
{buttonText}
</Button>
);
if (
processInstance.status === 'not_started' ||
processInstance.status === 'user_input_required' ||

View File

@ -96,7 +96,7 @@ export default function ProcessInstanceRun({
const onProcessInstanceRun = (processInstance: any) => {
const processInstanceId = (processInstance as any).id;
navigate(
`/process/${modifyProcessIdentifierForPathParam(
`/admin/process-instances/${modifyProcessIdentifierForPathParam(
processModel.id
)}/${processInstanceId}/interstitial`
);

View File

@ -2,33 +2,32 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { fetchEventSource } from '@microsoft/fetch-event-source';
// @ts-ignore
import { Loading, Button } from '@carbon/react';
import { Loading } from '@carbon/react';
import { BACKEND_BASE_URL } from '../config';
import { getBasicHeaders } from '../services/HttpService';
// @ts-ignore
import InstructionsForEndUser from './InstructionsForEndUser';
import ProcessBreadcrumb from './ProcessBreadcrumb';
import { ProcessInstance, ProcessInstanceTask } from '../interfaces';
import useAPIError from '../hooks/UseApiError';
type OwnProps = {
processInstanceId: number;
modifiedProcessModelIdentifier: string;
processInstanceShowPageUrl: string;
allowRedirect: boolean;
};
export default function ProcessInterstitial({
processInstanceId,
modifiedProcessModelIdentifier,
allowRedirect,
processInstanceShowPageUrl,
}: OwnProps) {
const [data, setData] = useState<any[]>([]);
const [lastTask, setLastTask] = useState<any>(null);
const [state, setState] = useState<string>('RUNNING');
const [processInstance, setProcessInstance] =
useState<ProcessInstance | null>(null);
const processInstanceShowPageBaseUrl = `/admin/process-instances/for-me/${modifiedProcessModelIdentifier}`;
const navigate = useNavigate();
const userTasks = useMemo(() => {
return ['User Task', 'Manual Task'];
@ -50,13 +49,14 @@ export default function ProcessInterstitial({
}
},
onclose() {
console.log('The state is closed.');
setState('CLOSED');
},
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // it is critical to only run this once.
const shouldRedirect = useCallback(
const shouldRedirectToTask = useCallback(
(myTask: ProcessInstanceTask): boolean => {
return (
allowRedirect &&
@ -66,21 +66,38 @@ export default function ProcessInterstitial({
userTasks.includes(myTask.type)
);
},
[userTasks, processInstance]
[allowRedirect, processInstance, userTasks]
);
const shouldRedirectToProcessInstance = useCallback((): boolean => {
return allowRedirect && state === 'CLOSED';
}, [allowRedirect, state]);
useEffect(() => {
// Added this seperate use effect so that the timer interval will be cleared if
// we end up redirecting back to the TaskShow page.
if (shouldRedirect(lastTask)) {
if (shouldRedirectToTask(lastTask)) {
lastTask.properties.instructionsForEndUser = '';
const timerId = setInterval(() => {
navigate(`/tasks/${lastTask.process_instance_id}/${lastTask.id}`);
}, 2000);
return () => clearInterval(timerId);
}
if (shouldRedirectToProcessInstance()) {
// Navigate without pause as we will be showing the same information.
navigate(processInstanceShowPageUrl);
}
return undefined;
}, [lastTask, navigate, userTasks, shouldRedirect]);
}, [
lastTask,
navigate,
userTasks,
shouldRedirectToTask,
processInstanceId,
processInstanceShowPageUrl,
state,
shouldRedirectToProcessInstance,
]);
const getStatus = (): string => {
if (processInstance) {
@ -101,35 +118,13 @@ export default function ProcessInterstitial({
<Loading
description="Active loading indicator"
withOverlay={false}
style={{ margin: 'auto' }}
style={{ margin: '50px 0 50px 50px' }}
/>
);
}
return null;
};
const getReturnHomeButton = (index: number) => {
if (
index === 0 &&
!shouldRedirect(lastTask) &&
['WAITING', 'ERROR', 'LOCKED', 'COMPLETED', 'READY'].includes(getStatus())
) {
return (
<div style={{ padding: '10px 0 0 0' }}>
<Button
kind="secondary"
data-qa="return-to-home-button"
onClick={() => navigate(`/tasks`)}
style={{ marginBottom: 30 }}
>
Return to Home
</Button>
</div>
);
}
return '';
};
const userMessage = (myTask: ProcessInstanceTask) => {
if (!processInstance || processInstance.status === 'completed') {
if (!myTask.can_complete && userTasks.includes(myTask.type)) {
@ -140,7 +135,7 @@ export default function ProcessInterstitial({
</p>
);
}
if (shouldRedirect(myTask)) {
if (shouldRedirectToTask(myTask)) {
return <div>Redirecting you to the next task now ...</div>;
}
if (myTask && myTask.can_complete && userTasks.includes(myTask.type)) {
@ -170,40 +165,24 @@ export default function ProcessInterstitial({
navigate(`/tasks`);
}
let displayableData = data;
if (state === 'CLOSED') {
displayableData = [data[0]];
}
if (lastTask) {
return (
<>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
{
entityToExplode: lastTask.process_model_identifier,
entityType: 'process-model-id',
linkLastItem: true,
},
[
`Process Instance: ${processInstanceId}`,
`${processInstanceShowPageBaseUrl}/${processInstanceId}`,
],
]}
/>
{getLoadingIcon()}
<div style={{ maxWidth: 800, margin: 'auto', padding: 50 }}>
{data.map((d, index) => (
<>
<div
className={
index < 4
? `user_instructions_${index}`
: `user_instructions_4`
}
>
{userMessage(d)}
</div>
{getReturnHomeButton(index)}
</>
))}
</div>
{displayableData.map((d, index) => (
<div
className={
index < 4 ? `user_instructions_${index}` : `user_instructions_4`
}
>
{userMessage(d)}
</div>
))}
</>
);
}

View File

@ -22,6 +22,7 @@ import Configuration from './Configuration';
import JsonSchemaFormBuilder from './JsonSchemaFormBuilder';
import ProcessModelNewExperimental from './ProcessModelNewExperimental';
import ProcessInstanceFindById from './ProcessInstanceFindById';
import ProcessInterstitialPage from "./ProcessInterstitialPage";
export default function AdminRoutes() {
const location = useLocation();
@ -75,6 +76,14 @@ export default function AdminRoutes() {
path="process-instances/for-me/:process_model_id/:process_instance_id/:to_task_guid"
element={<ProcessInstanceShow variant="for-me" />}
/>
<Route
path="process-instances/for-me/:process_model_id/:process_instance_id/interstitial"
element={<ProcessInterstitialPage variant="for-me" />}
/>
<Route
path="process-instances/:process_model_id/:process_instance_id/interstitial"
element={<ProcessInterstitialPage variant="all" />}
/>
<Route
path="process-instances/:process_model_id/:process_instance_id"
element={<ProcessInstanceShow variant="all" />}

View File

@ -53,7 +53,7 @@ import { usePermissionFetcher } from '../hooks/PermissionService';
import ProcessInstanceClass from '../classes/ProcessInstanceClass';
import TaskListTable from '../components/TaskListTable';
import useAPIError from '../hooks/UseApiError';
import ProcessInterstitial from "../components/ProcessInterstitial";
import ProcessInterstitial from '../components/ProcessInterstitial';
type OwnProps = {
variant: string;
@ -1093,9 +1093,28 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
return (
<>
<ProcessInterstitial processInstanceId={processInstance.id} modifiedProcessModelIdentifier={String(modifiedProcessModelId)} allowRedirect={false}/>
{buttonIcons()}
<br />
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
{
entityToExplode: processModelId,
entityType: 'process-model-id',
linkLastItem: true,
},
[`Process Instance Id: ${processInstance.id}`],
]}
/>
<Stack orientation="horizontal" gap={1}>
<h1 className="with-icons">
Process Instance Id: {processInstance.id}
</h1>
{buttonIcons()}
</Stack>
<ProcessInterstitial
processInstanceId={processInstance.id}
processInstanceShowPageUrl={processInstanceShowPageBaseUrl}
allowRedirect={false}
/>
<br />
<br />
<Grid condensed fullWidth>

View File

@ -2,17 +2,42 @@ import React from 'react';
import { useParams } from 'react-router-dom';
// @ts-ignore
import ProcessInterstitial from '../components/ProcessInterstitial';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
export default function ProcessInterstitialPage() {
type OwnProps = {
variant: string;
};
export default function ProcessInterstitialPage({ variant }: OwnProps) {
const params = useParams();
let processInstanceShowPageUrl = `/admin/process-instances/for-me/${params.process_model_id}/${params.process_instance_id}`;
if (variant === 'all') {
processInstanceShowPageUrl = `/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`;
}
// @ts-ignore
console.log('params', params, processInstanceShowPageUrl);
return (
<ProcessInterstitial
processInstanceId={Number(params.process_instance_id)}
modifiedProcessModelIdentifier={String(
params.modified_process_model_identifier
)}
allowRedirect
/>
<>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
{
entityToExplode: String(params.process_model_id),
entityType: 'process-model-id',
linkLastItem: true,
},
[
`Process Instance: ${params.process_instance_id}`,
`${processInstanceShowPageUrl}`,
],
]}
/>
<ProcessInterstitial
processInstanceId={Number(params.process_instance_id)}
processInstanceShowPageUrl={processInstanceShowPageUrl}
allowRedirect
/>
</>
);
}

View File

@ -1,14 +0,0 @@
import { Route, Routes } from 'react-router-dom';
// @ts-ignore
import ProcessInterstitialPage from './ProcessInterstitialPage';
export default function ProcessRoutes() {
return (
<Routes>
<Route
path=":modified_process_model_identifier/:process_instance_id/interstitial"
element={<ProcessInterstitialPage />}
/>
</Routes>
);
}

View File

@ -102,7 +102,7 @@ export default function TaskShow() {
const navigateToInterstitial = (myTask: Task) => {
navigate(
`/process/${modifyProcessIdentifierForPathParam(
`/admin/process-instances/${modifyProcessIdentifierForPathParam(
myTask.process_model_identifier
)}/${myTask.process_instance_id}/interstitial`
);