diff --git a/spiffworkflow-frontend/src/App.tsx b/spiffworkflow-frontend/src/App.tsx
index cddc3061..97d14fcc 100644
--- a/spiffworkflow-frontend/src/App.tsx
+++ b/spiffworkflow-frontend/src/App.tsx
@@ -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() {
} />
} />
} />
- } />
} />
diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx
index 2b53d724..268debab 100644
--- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx
+++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx
@@ -782,7 +782,7 @@ export default function ProcessInstanceListTable({
undefined,
paginationQueryParamPrefix
);
- page = 1; // Reset page back to 0
+ page = 1;
const newReportMetadata = getNewReportMetadataBasedOnPageWidgets();
setReportMetadata(newReportMetadata);
@@ -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 = (
+
+ Go
+
+ );
}
- buttonElement = (
-
- {buttonText}
-
- );
-
if (
processInstance.status === 'not_started' ||
processInstance.status === 'user_input_required' ||
diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx
index 22cd3ac3..0f61e128 100644
--- a/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx
+++ b/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx
@@ -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`
);
diff --git a/spiffworkflow-frontend/src/routes/ProcessInterstitial.tsx b/spiffworkflow-frontend/src/components/ProcessInterstitial.tsx
similarity index 54%
rename from spiffworkflow-frontend/src/routes/ProcessInterstitial.tsx
rename to spiffworkflow-frontend/src/components/ProcessInterstitial.tsx
index c906a0cd..639b5bb9 100644
--- a/spiffworkflow-frontend/src/routes/ProcessInterstitial.tsx
+++ b/spiffworkflow-frontend/src/components/ProcessInterstitial.tsx
@@ -1,80 +1,103 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import { useNavigate, useParams } from 'react-router-dom';
+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 '../components/InstructionsForEndUser';
-import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
+import InstructionsForEndUser from './InstructionsForEndUser';
import { ProcessInstance, ProcessInstanceTask } from '../interfaces';
import useAPIError from '../hooks/UseApiError';
-export default function ProcessInterstitial() {
+type OwnProps = {
+ processInstanceId: number;
+ processInstanceShowPageUrl: string;
+ allowRedirect: boolean;
+};
+
+export default function ProcessInterstitial({
+ processInstanceId,
+ allowRedirect,
+ processInstanceShowPageUrl,
+}: OwnProps) {
const [data, setData] = useState([]);
const [lastTask, setLastTask] = useState(null);
+ const [state, setState] = useState('RUNNING');
const [processInstance, setProcessInstance] =
useState(null);
- const [state, setState] = useState('RUNNING');
- const params = useParams();
+
const navigate = useNavigate();
const userTasks = useMemo(() => {
return ['User Task', 'Manual Task'];
}, []);
const { addError } = useAPIError();
- const processInstanceShowPageBaseUrl = `/admin/process-instances/for-me/${params.modified_process_model_identifier}`;
-
useEffect(() => {
- fetchEventSource(
- `${BACKEND_BASE_URL}/tasks/${params.process_instance_id}`,
- {
- headers: getBasicHeaders(),
- onmessage(ev) {
- const retValue = JSON.parse(ev.data);
- if (retValue.type === 'error') {
- addError(retValue.error);
- } else if (retValue.type === 'task') {
- setData((prevData) => [retValue.task, ...prevData]);
- setLastTask(retValue.task);
- } else if (retValue.type === 'unrunnable_instance') {
- setProcessInstance(retValue.unrunnable_instance);
- }
- },
- onclose() {
- setState('CLOSED');
- },
- }
- );
+ fetchEventSource(`${BACKEND_BASE_URL}/tasks/${processInstanceId}`, {
+ headers: getBasicHeaders(),
+ onmessage(ev) {
+ const retValue = JSON.parse(ev.data);
+ if (retValue.type === 'error') {
+ addError(retValue.error);
+ } else if (retValue.type === 'task') {
+ setData((prevData) => [retValue.task, ...prevData]);
+ setLastTask(retValue.task);
+ } else if (retValue.type === 'unrunnable_instance') {
+ setProcessInstance(retValue.unrunnable_instance);
+ }
+ },
+ 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 &&
!processInstance &&
myTask &&
myTask.can_complete &&
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) {
@@ -95,35 +118,13 @@ export default function ProcessInterstitial() {
);
}
return null;
};
- const getReturnHomeButton = (index: number) => {
- if (
- index === 0 &&
- !shouldRedirect(lastTask) &&
- ['WAITING', 'ERROR', 'LOCKED', 'COMPLETED', 'READY'].includes(getStatus())
- ) {
- return (
-
- navigate(`/tasks`)}
- style={{ marginBottom: 30 }}
- >
- Return to Home
-
-
- );
- }
- return '';
- };
-
const userMessage = (myTask: ProcessInstanceTask) => {
if (!processInstance || processInstance.status === 'completed') {
if (!myTask.can_complete && userTasks.includes(myTask.type)) {
@@ -134,9 +135,12 @@ export default function ProcessInterstitial() {
);
}
- if (shouldRedirect(myTask)) {
+ if (shouldRedirectToTask(myTask)) {
return Redirecting you to the next task now ...
;
}
+ if (myTask && myTask.can_complete && userTasks.includes(myTask.type)) {
+ return `The task ${myTask.title} is ready for you to complete.`;
+ }
if (myTask.error_message) {
return {myTask.error_message}
;
}
@@ -161,40 +165,24 @@ export default function ProcessInterstitial() {
navigate(`/tasks`);
}
+ let displayableData = data;
+ if (state === 'CLOSED') {
+ displayableData = [data[0]];
+ }
+
if (lastTask) {
return (
<>
-
{getLoadingIcon()}
-
- {data.map((d, index) => (
- <>
-
- {userMessage(d)}
-
- {getReturnHomeButton(index)}
- >
- ))}
-
+ {displayableData.map((d, index) => (
+
+ {userMessage(d)}
+
+ ))}
>
);
}
diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts
index 81a56326..139a0107 100644
--- a/spiffworkflow-frontend/src/interfaces.ts
+++ b/spiffworkflow-frontend/src/interfaces.ts
@@ -23,6 +23,7 @@ export interface RecentProcessModel {
export interface TaskPropertiesJson {
parent: string;
+ last_state_change: number;
}
export interface TaskDefinitionPropertiesJson {
diff --git a/spiffworkflow-frontend/src/routes/AdminRoutes.tsx b/spiffworkflow-frontend/src/routes/AdminRoutes.tsx
index 0e9df5d9..05b5d295 100644
--- a/spiffworkflow-frontend/src/routes/AdminRoutes.tsx
+++ b/spiffworkflow-frontend/src/routes/AdminRoutes.tsx
@@ -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={ }
/>
+ }
+ />
+ }
+ />
}
diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx
index 8650cc00..ca7968a2 100644
--- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx
+++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx
@@ -53,6 +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';
type OwnProps = {
variant: string;
@@ -1109,6 +1110,11 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
{buttonIcons()}
+
diff --git a/spiffworkflow-frontend/src/routes/ProcessInterstitialPage.tsx b/spiffworkflow-frontend/src/routes/ProcessInterstitialPage.tsx
new file mode 100644
index 00000000..7d633103
--- /dev/null
+++ b/spiffworkflow-frontend/src/routes/ProcessInterstitialPage.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { useParams } from 'react-router-dom';
+// @ts-ignore
+import ProcessInterstitial from '../components/ProcessInterstitial';
+import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
+
+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}`;
+ }
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/spiffworkflow-frontend/src/routes/ProcessRoutes.tsx b/spiffworkflow-frontend/src/routes/ProcessRoutes.tsx
deleted file mode 100644
index dc8a1d66..00000000
--- a/spiffworkflow-frontend/src/routes/ProcessRoutes.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Route, Routes } from 'react-router-dom';
-// @ts-ignore
-import ProcessInterstitial from './ProcessInterstitial';
-
-export default function ProcessRoutes() {
- return (
-
- }
- />
-
- );
-}
diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx
index af8f9446..29310eef 100644
--- a/spiffworkflow-frontend/src/routes/TaskShow.tsx
+++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx
@@ -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`
);