added a loading icon on task show page to avoid blank page when loadi… (#411)
* added a loading icon on task show page to avoid blank page when loading large datasets w/ burnettk * fixed broken tests w/ burnettk --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
c416a5a05e
commit
6a922b2eb4
|
@ -1904,6 +1904,12 @@ paths:
|
|||
description: The unique id of an existing process instance.
|
||||
schema:
|
||||
type: integer
|
||||
- name: with_form_data
|
||||
in: query
|
||||
required: false
|
||||
description: Include task data for forms
|
||||
schema:
|
||||
type: boolean
|
||||
get:
|
||||
tags:
|
||||
- Tasks
|
||||
|
|
|
@ -300,7 +300,9 @@ def task_assign(
|
|||
return make_response(jsonify({"ok": True}), 200)
|
||||
|
||||
|
||||
def task_show(process_instance_id: int, task_guid: str = "next") -> flask.wrappers.Response:
|
||||
def task_show(
|
||||
process_instance_id: int, task_guid: str = "next", with_form_data: bool = False
|
||||
) -> flask.wrappers.Response:
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
|
||||
if process_instance.status == ProcessInstanceStatus.suspended.value:
|
||||
|
@ -314,20 +316,8 @@ def task_show(process_instance_id: int, task_guid: str = "next") -> flask.wrappe
|
|||
process_instance.process_model_identifier,
|
||||
)
|
||||
|
||||
form_schema_file_name = ""
|
||||
form_ui_schema_file_name = ""
|
||||
|
||||
task_model = _get_task_model_from_guid_or_raise(task_guid, process_instance_id)
|
||||
task_definition = task_model.task_definition
|
||||
extensions = TaskService.get_extensions_from_task_model(task_model)
|
||||
task_model.signal_buttons = TaskService.get_ready_signals_with_button_labels(process_instance_id, task_model.guid)
|
||||
|
||||
if "properties" in extensions:
|
||||
properties = extensions["properties"]
|
||||
if "formJsonSchemaFilename" in properties:
|
||||
form_schema_file_name = properties["formJsonSchemaFilename"]
|
||||
if "formUiSchemaFilename" in properties:
|
||||
form_ui_schema_file_name = properties["formUiSchemaFilename"]
|
||||
|
||||
can_complete = False
|
||||
try:
|
||||
|
@ -336,71 +326,89 @@ def task_show(process_instance_id: int, task_guid: str = "next") -> flask.wrappe
|
|||
except (HumanTaskNotFoundError, UserDoesNotHaveAccessToTaskError, HumanTaskAlreadyCompletedError):
|
||||
can_complete = False
|
||||
|
||||
task_draft_data = TaskService.task_draft_data_from_task_model(task_model)
|
||||
|
||||
saved_form_data = None
|
||||
if task_draft_data is not None:
|
||||
saved_form_data = task_draft_data.get_saved_form_data()
|
||||
|
||||
task_model.data = task_model.get_data()
|
||||
task_model.saved_form_data = saved_form_data
|
||||
task_model.process_model_display_name = process_model.display_name
|
||||
task_model.process_model_identifier = process_model.id
|
||||
task_model.typename = task_definition.typename
|
||||
task_model.can_complete = can_complete
|
||||
task_process_identifier = task_model.bpmn_process.bpmn_process_definition.bpmn_identifier
|
||||
task_model.name_for_display = TaskService.get_name_for_display(task_definition)
|
||||
|
||||
process_model_with_form = process_model
|
||||
if with_form_data:
|
||||
task_process_identifier = task_model.bpmn_process.bpmn_process_definition.bpmn_identifier
|
||||
process_model_with_form = process_model
|
||||
|
||||
refs = SpecFileService.get_references_for_process(process_model_with_form)
|
||||
all_processes = [i.identifier for i in refs]
|
||||
if task_process_identifier not in all_processes:
|
||||
top_bpmn_process = TaskService.bpmn_process_for_called_activity_or_top_level_process(task_model)
|
||||
bpmn_file_full_path = ProcessInstanceProcessor.bpmn_file_full_path_from_bpmn_process_identifier(
|
||||
top_bpmn_process.bpmn_process_definition.bpmn_identifier
|
||||
)
|
||||
relative_path = os.path.relpath(bpmn_file_full_path, start=FileSystemService.root_path())
|
||||
process_model_relative_path = os.path.dirname(relative_path)
|
||||
process_model_with_form = ProcessModelService.get_process_model_from_relative_path(process_model_relative_path)
|
||||
|
||||
if task_definition.typename == "UserTask":
|
||||
if not form_schema_file_name:
|
||||
raise (
|
||||
ApiError(
|
||||
error_code="missing_form_file",
|
||||
message=(
|
||||
f"Cannot find a form file for process_instance_id: {process_instance_id}, task_guid:"
|
||||
f" {task_guid}"
|
||||
),
|
||||
status_code=400,
|
||||
)
|
||||
refs = SpecFileService.get_references_for_process(process_model_with_form)
|
||||
all_processes = [i.identifier for i in refs]
|
||||
if task_process_identifier not in all_processes:
|
||||
top_bpmn_process = TaskService.bpmn_process_for_called_activity_or_top_level_process(task_model)
|
||||
bpmn_file_full_path = ProcessInstanceProcessor.bpmn_file_full_path_from_bpmn_process_identifier(
|
||||
top_bpmn_process.bpmn_process_definition.bpmn_identifier
|
||||
)
|
||||
relative_path = os.path.relpath(bpmn_file_full_path, start=FileSystemService.root_path())
|
||||
process_model_relative_path = os.path.dirname(relative_path)
|
||||
process_model_with_form = ProcessModelService.get_process_model_from_relative_path(
|
||||
process_model_relative_path
|
||||
)
|
||||
|
||||
form_dict = _prepare_form_data(
|
||||
form_schema_file_name,
|
||||
task_model,
|
||||
process_model_with_form,
|
||||
form_schema_file_name = ""
|
||||
form_ui_schema_file_name = ""
|
||||
extensions = TaskService.get_extensions_from_task_model(task_model)
|
||||
task_model.signal_buttons = TaskService.get_ready_signals_with_button_labels(
|
||||
process_instance_id, task_model.guid
|
||||
)
|
||||
|
||||
if task_model.data:
|
||||
_update_form_schema_with_task_data_as_needed(form_dict, task_model)
|
||||
if "properties" in extensions:
|
||||
properties = extensions["properties"]
|
||||
if "formJsonSchemaFilename" in properties:
|
||||
form_schema_file_name = properties["formJsonSchemaFilename"]
|
||||
if "formUiSchemaFilename" in properties:
|
||||
form_ui_schema_file_name = properties["formUiSchemaFilename"]
|
||||
|
||||
if form_dict:
|
||||
task_model.form_schema = form_dict
|
||||
task_draft_data = TaskService.task_draft_data_from_task_model(task_model)
|
||||
|
||||
if form_ui_schema_file_name:
|
||||
ui_form_contents = _prepare_form_data(
|
||||
form_ui_schema_file_name,
|
||||
saved_form_data = None
|
||||
if task_draft_data is not None:
|
||||
saved_form_data = task_draft_data.get_saved_form_data()
|
||||
|
||||
task_model.data = task_model.get_data()
|
||||
task_model.saved_form_data = saved_form_data
|
||||
if task_definition.typename == "UserTask":
|
||||
if not form_schema_file_name:
|
||||
raise (
|
||||
ApiError(
|
||||
error_code="missing_form_file",
|
||||
message=(
|
||||
f"Cannot find a form file for process_instance_id: {process_instance_id}, task_guid:"
|
||||
f" {task_guid}"
|
||||
),
|
||||
status_code=400,
|
||||
)
|
||||
)
|
||||
|
||||
form_dict = _prepare_form_data(
|
||||
form_schema_file_name,
|
||||
task_model,
|
||||
process_model_with_form,
|
||||
)
|
||||
if ui_form_contents:
|
||||
task_model.form_ui_schema = ui_form_contents
|
||||
|
||||
_munge_form_ui_schema_based_on_hidden_fields_in_task_data(task_model)
|
||||
JinjaService.render_instructions_for_end_user(task_model, extensions)
|
||||
task_model.extensions = extensions
|
||||
if task_model.data:
|
||||
_update_form_schema_with_task_data_as_needed(form_dict, task_model)
|
||||
|
||||
if form_dict:
|
||||
task_model.form_schema = form_dict
|
||||
|
||||
if form_ui_schema_file_name:
|
||||
ui_form_contents = _prepare_form_data(
|
||||
form_ui_schema_file_name,
|
||||
task_model,
|
||||
process_model_with_form,
|
||||
)
|
||||
if ui_form_contents:
|
||||
task_model.form_ui_schema = ui_form_contents
|
||||
|
||||
_munge_form_ui_schema_based_on_hidden_fields_in_task_data(task_model)
|
||||
JinjaService.render_instructions_for_end_user(task_model, extensions)
|
||||
task_model.extensions = extensions
|
||||
|
||||
return make_response(jsonify(task_model), 200)
|
||||
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ class TestForGoodErrors(BaseTest):
|
|||
assert len(human_tasks) > 0, "No human tasks found for process."
|
||||
human_task = human_tasks[0]
|
||||
response = client.get(
|
||||
f"/v1.0/tasks/{process_instance_id}/{human_task.task_id}",
|
||||
f"/v1.0/tasks/{process_instance_id}/{human_task.task_id}?with_form_data=true",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
)
|
||||
return response
|
||||
|
|
|
@ -55,7 +55,7 @@ class TestTasksController(BaseTest):
|
|||
assert len(human_tasks) == 1
|
||||
human_task = human_tasks[0]
|
||||
response = client.get(
|
||||
f"/v1.0/tasks/{process_instance_id}/{human_task.task_id}",
|
||||
f"/v1.0/tasks/{process_instance_id}/{human_task.task_id}?with_form_data=true",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
@ -173,7 +173,7 @@ class TestTasksController(BaseTest):
|
|||
assert json_results[1]["task"]["title"] == "Manual Task"
|
||||
|
||||
response = client.put(
|
||||
f"/v1.0/tasks/{process_instance_id}/{json_results[1]['task']['id']}",
|
||||
f"/v1.0/tasks/{process_instance_id}/{json_results[1]['task']['id']}?with_form_data=true",
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
|
@ -204,7 +204,7 @@ class TestTasksController(BaseTest):
|
|||
|
||||
# Complete task as the finance user.
|
||||
response = client.put(
|
||||
f"/v1.0/tasks/{process_instance_id}/{json_results[0]['task']['id']}",
|
||||
f"/v1.0/tasks/{process_instance_id}/{json_results[0]['task']['id']}?with_form_data=true",
|
||||
headers=self.logged_in_headers(finance_user),
|
||||
)
|
||||
|
||||
|
@ -363,7 +363,7 @@ class TestTasksController(BaseTest):
|
|||
assert response.status_code == 200
|
||||
|
||||
response = client.get(
|
||||
f"/v1.0/tasks/{process_instance_id}/{task_id}",
|
||||
f"/v1.0/tasks/{process_instance_id}/{task_id}?with_form_data=true",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
@ -380,7 +380,7 @@ class TestTasksController(BaseTest):
|
|||
|
||||
# ensure draft data is deleted after submitting the task
|
||||
response = client.get(
|
||||
f"/v1.0/tasks/{process_instance_id}/{task_id}",
|
||||
f"/v1.0/tasks/{process_instance_id}/{task_id}?with_form_data=true",
|
||||
headers=self.logged_in_headers(with_super_admin_user),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
|
|
@ -51,8 +51,8 @@ export interface SignalButton {
|
|||
event: EventDefinition;
|
||||
}
|
||||
|
||||
// TODO: merge with ProcessInstanceTask
|
||||
export interface Task {
|
||||
// Task withouth task data and form info - just the basics
|
||||
export interface BasicTask {
|
||||
id: number;
|
||||
guid: string;
|
||||
process_instance_id: number;
|
||||
|
@ -60,25 +60,30 @@ export interface Task {
|
|||
bpmn_name?: string;
|
||||
bpmn_process_direct_parent_guid: string;
|
||||
bpmn_process_definition_identifier: string;
|
||||
data: any;
|
||||
state: string;
|
||||
typename: string;
|
||||
properties_json: TaskPropertiesJson;
|
||||
task_definition_properties_json: TaskDefinitionPropertiesJson;
|
||||
|
||||
event_definition?: EventDefinition;
|
||||
|
||||
process_model_display_name: string;
|
||||
process_model_identifier: string;
|
||||
name_for_display: string;
|
||||
can_complete: boolean;
|
||||
}
|
||||
|
||||
// TODO: merge with ProcessInstanceTask
|
||||
// Currently used like TaskModel in backend
|
||||
export interface Task extends BasicTask {
|
||||
data: any;
|
||||
form_schema: any;
|
||||
form_ui_schema: any;
|
||||
signal_buttons: SignalButton[];
|
||||
|
||||
event_definition?: EventDefinition;
|
||||
saved_form_data?: any;
|
||||
}
|
||||
|
||||
// Currently used like ApiTask in backend
|
||||
export interface ProcessInstanceTask {
|
||||
id: string;
|
||||
task_id: string;
|
||||
|
|
|
@ -2,15 +2,7 @@ import React, { useEffect, useState } from 'react';
|
|||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import validator from '@rjsf/validator-ajv8';
|
||||
|
||||
import {
|
||||
TabList,
|
||||
Tab,
|
||||
Tabs,
|
||||
Grid,
|
||||
Column,
|
||||
Button,
|
||||
ButtonSet,
|
||||
} from '@carbon/react';
|
||||
import { Grid, Column, Button, ButtonSet, Loading } from '@carbon/react';
|
||||
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { Form } from '../rjsf/carbon_theme';
|
||||
|
@ -21,7 +13,7 @@ import {
|
|||
modifyProcessIdentifierForPathParam,
|
||||
recursivelyChangeNullAndUndefined,
|
||||
} from '../helpers';
|
||||
import { EventDefinition, Task } from '../interfaces';
|
||||
import { BasicTask, EventDefinition, Task } from '../interfaces';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import InstructionsForEndUser from '../components/InstructionsForEndUser';
|
||||
import TypeaheadWidget from '../rjsf/custom_widgets/TypeaheadWidget/TypeaheadWidget';
|
||||
|
@ -29,8 +21,8 @@ import DateRangePickerWidget from '../rjsf/custom_widgets/DateRangePicker/DateRa
|
|||
import { DATE_RANGE_DELIMITER } from '../config';
|
||||
|
||||
export default function TaskShow() {
|
||||
const [task, setTask] = useState<Task | null>(null);
|
||||
const [userTasks] = useState(null);
|
||||
const [basicTask, setBasicTask] = useState<BasicTask | null>(null);
|
||||
const [taskWithTaskData, setTaskWithTaskData] = useState<Task | null>(null);
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const [formButtonsDisabled, setFormButtonsDisabled] = useState(false);
|
||||
|
@ -48,7 +40,7 @@ export default function TaskShow() {
|
|||
|
||||
// if a user can complete a task then the for-me page should
|
||||
// always work for them so use that since it will work in all cases
|
||||
const navigateToInterstitial = (myTask: Task) => {
|
||||
const navigateToInterstitial = (myTask: BasicTask) => {
|
||||
navigate(
|
||||
`/admin/process-instances/for-me/${modifyProcessIdentifierForPathParam(
|
||||
myTask.process_model_identifier
|
||||
|
@ -57,20 +49,29 @@ export default function TaskShow() {
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
const processResult = (result: Task) => {
|
||||
setTask(result);
|
||||
const processBasicTaskResult = (result: BasicTask) => {
|
||||
setBasicTask(result);
|
||||
if (!result.can_complete) {
|
||||
navigateToInterstitial(result);
|
||||
}
|
||||
};
|
||||
const processTaskWithDataResult = (result: Task) => {
|
||||
setTaskWithTaskData(result);
|
||||
|
||||
// convert null back to undefined so rjsf doesn't attempt to incorrectly validate them
|
||||
const taskDataToUse = result.saved_form_data || result.data;
|
||||
setTaskData(recursivelyChangeNullAndUndefined(taskDataToUse, undefined));
|
||||
setFormButtonsDisabled(false);
|
||||
if (!result.can_complete) {
|
||||
navigateToInterstitial(result);
|
||||
}
|
||||
};
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/tasks/${params.process_instance_id}/${params.task_id}`,
|
||||
successCallback: processResult,
|
||||
successCallback: processBasicTaskResult,
|
||||
failureCallback: addError,
|
||||
});
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/tasks/${params.process_instance_id}/${params.task_id}?with_form_data=true`,
|
||||
successCallback: processTaskWithDataResult,
|
||||
failureCallback: addError,
|
||||
});
|
||||
// FIXME: not sure what to do about addError. adding it to this array causes the page to endlessly reload
|
||||
|
@ -83,7 +84,7 @@ export default function TaskShow() {
|
|||
// https://github.com/sartography/spiff-arena/blob/182f56a1ad23ce780e8f5b0ed00efac3e6ad117b/spiffworkflow-frontend/src/routes/TaskShow.tsx#L329
|
||||
const autoSaveTaskData = (formData: any, successCallback?: Function) => {
|
||||
// save-draft gets called when a manual task form loads but there's no data to save so don't do it
|
||||
if (task?.typename === 'ManualTask') {
|
||||
if (taskWithTaskData?.typename === 'ManualTask') {
|
||||
return undefined;
|
||||
}
|
||||
let successCallbackToUse = successCallback;
|
||||
|
@ -180,7 +181,7 @@ export default function TaskShow() {
|
|||
};
|
||||
|
||||
const handleSignalSubmit = (event: EventDefinition) => {
|
||||
if (formButtonsDisabled || !task) {
|
||||
if (formButtonsDisabled || !taskWithTaskData) {
|
||||
return;
|
||||
}
|
||||
setFormButtonsDisabled(true);
|
||||
|
@ -195,58 +196,6 @@ export default function TaskShow() {
|
|||
});
|
||||
};
|
||||
|
||||
const buildTaskNavigation = () => {
|
||||
let userTasksElement;
|
||||
let selectedTabIndex = 0;
|
||||
if (userTasks) {
|
||||
userTasksElement = (userTasks as any).map(function getUserTasksElement(
|
||||
userTask: any,
|
||||
index: number
|
||||
) {
|
||||
const taskUrl = `/tasks/${params.process_instance_id}/${userTask.id}`;
|
||||
if (userTask.id === params.task_id) {
|
||||
selectedTabIndex = index;
|
||||
return <Tab selected>{userTask.name_for_display}</Tab>;
|
||||
}
|
||||
if (userTask.state === 'COMPLETED') {
|
||||
return (
|
||||
<Tab
|
||||
onClick={() => navigate(taskUrl)}
|
||||
data-qa={`form-nav-${userTask.name}`}
|
||||
>
|
||||
{userTask.name_for_display}
|
||||
</Tab>
|
||||
);
|
||||
}
|
||||
if (userTask.state === 'FUTURE') {
|
||||
return <Tab formButtonsDisabled>{userTask.name_for_display}</Tab>;
|
||||
}
|
||||
if (userTask.state === 'READY') {
|
||||
return (
|
||||
<Tab
|
||||
onClick={() => navigate(taskUrl)}
|
||||
data-qa={`form-nav-${userTask.name}`}
|
||||
>
|
||||
{userTask.name_for_display}
|
||||
</Tab>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
return (
|
||||
<Tabs
|
||||
title="Steps in this process instance involving people"
|
||||
selectedIndex={selectedTabIndex}
|
||||
>
|
||||
<TabList aria-label="List of tabs" contained>
|
||||
{userTasksElement}
|
||||
</TabList>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const formatDateString = (dateString?: string) => {
|
||||
let dateObject = new Date();
|
||||
if (dateString) {
|
||||
|
@ -406,14 +355,14 @@ export default function TaskShow() {
|
|||
};
|
||||
|
||||
const formElement = () => {
|
||||
if (!task) {
|
||||
if (!taskWithTaskData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let formUiSchema;
|
||||
let jsonSchema = task.form_schema;
|
||||
let jsonSchema = taskWithTaskData.form_schema;
|
||||
let reactFragmentToHideSubmitButton = null;
|
||||
if (task.typename === 'ManualTask') {
|
||||
if (taskWithTaskData.typename === 'ManualTask') {
|
||||
jsonSchema = {
|
||||
type: 'object',
|
||||
required: [],
|
||||
|
@ -430,10 +379,10 @@ export default function TaskShow() {
|
|||
'ui:widget': 'hidden',
|
||||
},
|
||||
};
|
||||
} else if (task.form_ui_schema) {
|
||||
formUiSchema = task.form_ui_schema;
|
||||
} else if (taskWithTaskData.form_ui_schema) {
|
||||
formUiSchema = taskWithTaskData.form_ui_schema;
|
||||
}
|
||||
if (task.state !== 'READY') {
|
||||
if (taskWithTaskData.state !== 'READY') {
|
||||
formUiSchema = Object.assign(formUiSchema || {}, {
|
||||
'ui:readonly': true,
|
||||
});
|
||||
|
@ -445,12 +394,12 @@ export default function TaskShow() {
|
|||
reactFragmentToHideSubmitButton = <div />;
|
||||
}
|
||||
|
||||
if (task.state === 'READY') {
|
||||
if (taskWithTaskData.state === 'READY') {
|
||||
let submitButtonText = 'Submit';
|
||||
let closeButton = null;
|
||||
if (task.typename === 'ManualTask') {
|
||||
if (taskWithTaskData.typename === 'ManualTask') {
|
||||
submitButtonText = 'Continue';
|
||||
} else if (task.typename === 'UserTask') {
|
||||
} else if (taskWithTaskData.typename === 'UserTask') {
|
||||
closeButton = (
|
||||
<Button
|
||||
id="close-button"
|
||||
|
@ -474,7 +423,7 @@ export default function TaskShow() {
|
|||
</Button>
|
||||
{closeButton}
|
||||
<>
|
||||
{task.signal_buttons.map((signal) => (
|
||||
{taskWithTaskData.signal_buttons.map((signal) => (
|
||||
<Button
|
||||
name="signal.signal"
|
||||
disabled={formButtonsDisabled}
|
||||
|
@ -532,35 +481,52 @@ export default function TaskShow() {
|
|||
);
|
||||
};
|
||||
|
||||
if (task) {
|
||||
const getLoadingIcon = () => {
|
||||
const style = { margin: '50px 0 50px 50px' };
|
||||
return (
|
||||
<Loading
|
||||
description="Active loading indicator"
|
||||
withOverlay={false}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const pageElements = [];
|
||||
if (basicTask) {
|
||||
let statusString = '';
|
||||
if (task.state !== 'READY') {
|
||||
statusString = ` ${task.state}`;
|
||||
if (basicTask.state !== 'READY') {
|
||||
statusString = ` ${basicTask.state}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProcessBreadcrumb
|
||||
hotCrumbs={[
|
||||
[
|
||||
`Process Instance Id: ${params.process_instance_id}`,
|
||||
`/admin/process-instances/for-me/${modifyProcessIdentifierForPathParam(
|
||||
task.process_model_identifier
|
||||
)}/${params.process_instance_id}`,
|
||||
],
|
||||
[`Task: ${task.name_for_display || task.id}`],
|
||||
]}
|
||||
/>
|
||||
<div>{buildTaskNavigation()}</div>
|
||||
<h3>
|
||||
Task: {task.name_for_display} ({task.process_model_display_name})
|
||||
{statusString}
|
||||
</h3>
|
||||
<InstructionsForEndUser task={task} />
|
||||
{formElement()}
|
||||
</>
|
||||
pageElements.push(
|
||||
<ProcessBreadcrumb
|
||||
hotCrumbs={[
|
||||
[
|
||||
`Process Instance Id: ${params.process_instance_id}`,
|
||||
`/admin/process-instances/for-me/${modifyProcessIdentifierForPathParam(
|
||||
basicTask.process_model_identifier
|
||||
)}/${params.process_instance_id}`,
|
||||
],
|
||||
[`Task: ${basicTask.name_for_display || basicTask.id}`],
|
||||
]}
|
||||
/>
|
||||
);
|
||||
pageElements.push(
|
||||
<h3>
|
||||
Task: {basicTask.name_for_display} (
|
||||
{basicTask.process_model_display_name}){statusString}
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
if (basicTask && taskData) {
|
||||
pageElements.push(<InstructionsForEndUser task={taskWithTaskData} />);
|
||||
pageElements.push(formElement());
|
||||
} else {
|
||||
pageElements.push(getLoadingIcon());
|
||||
}
|
||||
|
||||
return null;
|
||||
// typescript gets angry if we return an array of elements not in a tag
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
return <>{pageElements}</>;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue