diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py index ccc463584..43ed6cef1 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py @@ -610,54 +610,6 @@ def process_instance_task_list( most_recent_tasks_only: bool = False, ) -> flask.wrappers.Response: """Process_instance_task_list.""" - # step_detail_query = db.session.query(SpiffStepDetailsModel).filter( - # SpiffStepDetailsModel.process_instance_id == process_instance.id, - # ) - # - # if spiff_step > 0: - # step_detail_query = step_detail_query.filter(SpiffStepDetailsModel.spiff_step <= spiff_step) - # - # step_details = step_detail_query.all() - # - # processor = ProcessInstanceProcessor(process_instance) - # full_bpmn_process_dict = processor.full_bpmn_process_dict - # tasks = full_bpmn_process_dict["tasks"] - # subprocesses = full_bpmn_process_dict["subprocesses"] - # - # steps_by_id = {step_detail.task_id: step_detail for step_detail in step_details} - # - # def restore_task(spiff_task: dict[str, Any], step_ended: float) -> None: - # if spiff_task["last_state_change"] > step_ended: - # spiff_task["state"] = Task.task_state_name_to_int("FUTURE") - # spiff_task["data"] = {} - # - # if spiff_step > 0: - # last_change = step_details[-1].end_in_seconds or 0 - # for spiff_task in tasks.values(): - # restore_task(spiff_task, last_change) - # for subprocess in subprocesses.values(): - # for spiff_task in subprocess["tasks"].values(): - # restore_task(spiff_task, last_change) - # - # bpmn_process_instance = ProcessInstanceProcessor._serializer.workflow_from_dict(full_bpmn_process_dict) - # if spiff_step > 0: - # bpmn_process_instance.complete_task_from_id(UUID(step_details[-1].task_id)) - # for subprocess_id, subprocess in bpmn_process_instance.subprocesses.items(): - # if not subprocess.is_completed(): - # task = bpmn_process_instance.get_task(subprocess_id) - # task._set_state(TaskState.WAITING) - - # guid: string; - # bpmn_identifier: string; - # - # bpmn_name?: string; - # - # state: string; - # typename: string; - - # calling_subprocess_task_guid: string; -> bpmn_process_direct_parent_guid - # call_activity_process_bpmn_identifier?: string; -> bpmn_process_direct_parent_bpmn_identifier - bpmn_process_ids = [] if bpmn_process_guid: bpmn_process = BpmnProcessModel.query.filter_by(guid=bpmn_process_guid).first() @@ -704,90 +656,24 @@ def process_instance_task_list( TaskDefinitionModel.bpmn_name, TaskDefinitionModel.typename, TaskDefinitionModel.properties_json.label('task_definition_properties_json'), # type: ignore + TaskModel.guid, + TaskModel.state, ) ) if len(bpmn_process_ids) > 0: - print(f"bpmn_process_ids: {bpmn_process_ids}") task_model_query = ( task_model_query.filter(bpmn_process_alias.id.in_(bpmn_process_ids)) ) task_models = task_model_query.all() - - # processor = ProcessInstanceProcessor(process_instance) - # full_bpmn_process_dict = processor.full_bpmn_process_dict - # tasks = full_bpmn_process_dict["tasks"] - # subprocesses = full_bpmn_process_dict["subprocesses"] - # - # steps_by_id = {step_detail.task_id: step_detail for step_detail in step_details} - # - # def restore_task(spiff_task: dict[str, Any], step_ended: float) -> None: - # if spiff_task["last_state_change"] > step_ended: - # spiff_task["state"] = Task.task_state_name_to_int("FUTURE") - # spiff_task["data"] = {} - # - # if spiff_step > 0: - # last_change = step_details[-1].end_in_seconds or 0 - # for spiff_task in tasks.values(): - # restore_task(spiff_task, last_change) - # for subprocess in subprocesses.values(): - # for spiff_task in subprocess["tasks"].values(): - # restore_task(spiff_task, last_change) - # - # bpmn_process_instance = ProcessInstanceProcessor._serializer.workflow_from_dict(full_bpmn_process_dict) - # if spiff_step > 0: - # bpmn_process_instance.complete_task_from_id(UUID(step_details[-1].task_id)) - # for subprocess_id, subprocess in bpmn_process_instance.subprocesses.items(): - # if not subprocess.is_completed(): - # task = bpmn_process_instance.get_task(subprocess_id) - # task._set_state(TaskState.WAITING) - - # spiff_tasks = None - # if all_tasks: - # spiff_tasks = bpmn_process_instance.get_tasks(TaskState.ANY_MASK) - # else: - # spiff_tasks = processor.get_all_user_tasks() - # - # ( - # subprocesses_by_child_task_ids, - # task_typename_by_task_id, - # ) = processor.get_subprocesses_by_child_task_ids() - # processor.get_highest_level_calling_subprocesses_by_child_task_ids( - # subprocesses_by_child_task_ids, task_typename_by_task_id - # ) - # - # spiff_tasks_to_process = spiff_tasks - # if most_recent_tasks_only: - # spiff_tasks_by_process_id_and_task_name: dict[str, SpiffTask] = {} - # current_tasks = {} - # for spiff_task in spiff_tasks_to_process: - # row_id = f"{spiff_task.task_spec._wf_spec.name}:{spiff_task.task_spec.name}" - # if spiff_task.state in [TaskState.READY, TaskState.WAITING]: - # current_tasks[row_id] = spiff_task - # if ( - # row_id not in spiff_tasks_by_process_id_and_task_name - # or spiff_task.state > spiff_tasks_by_process_id_and_task_name[row_id].state - # ): - # spiff_tasks_by_process_id_and_task_name[row_id] = spiff_task - # spiff_tasks_by_process_id_and_task_name.update(current_tasks) - # spiff_tasks_to_process = spiff_tasks_by_process_id_and_task_name.values() - # - # response = [] - # for spiff_task in spiff_tasks_to_process: - # task_spiff_step: Optional[int] = None - # if str(spiff_task.id) in steps_by_id: - # task_spiff_step = steps_by_id[str(spiff_task.id)].spiff_step - # calling_subprocess_task_id = subprocesses_by_child_task_ids.get(str(spiff_task.id), None) - # task = ProcessInstanceService.spiff_task_to_api_task( - # processor, - # spiff_task, - # calling_subprocess_task_id=calling_subprocess_task_id, - # task_spiff_step=task_spiff_step, - # ) - # if task.state in ["MAYBE", "LIKELY"]: - # task.state = "FUTURE" - # response.append(task) + # import pdb; pdb.set_trace() + if to_task_guid is not None: + task_models_dict = json.loads(current_app.json.dumps(task_models)) + for task_model in task_models_dict: + if task_model['guid'] == to_task_guid and task_model['state'] == "COMPLETED": + task_model['state'] = "READY" + return make_response(jsonify(task_models_dict), 200) return make_response(jsonify(task_models), 200) diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index 8b61f4745..4e65bd020 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -21,10 +21,22 @@ export interface RecentProcessModel { processModelDisplayName: string; } +export interface TaskPropertiesJson { + parent: string; +} + export interface TaskDefinitionPropertiesJson { spec: string; } +export interface EventDefinition { + typename: string; + payload: any; + event_definitions: [EventDefinition]; + + message_var?: string; +} + export interface Task { id: number; guid: string; @@ -37,12 +49,20 @@ export interface Task { data: any; state: string; typename: string; + properties_json: TaskPropertiesJson; task_definition_properties_json: TaskDefinitionPropertiesJson; + event_definition?: EventDefinition; + // TOOD: DELETE THIS! task_spiff_step?: number; } +export interface TaskIds { + completed: Task[]; + readyOrWaiting: Task[]; +} + export interface ProcessInstanceTask { id: string; task_id: string; diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 932314070..fb5b9b3bc 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -42,12 +42,14 @@ import { import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; import { useUriListForPermissions } from '../hooks/UriListForPermissions'; import { + EventDefinition, PermissionsToCheck, ProcessData, ProcessInstance, ProcessInstanceMetadata, Task, TaskDefinitionPropertiesJson, + TaskIds, } from '../interfaces'; import { usePermissionFetcher } from '../hooks/PermissionService'; import ProcessInstanceClass from '../classes/ProcessInstanceClass'; @@ -215,14 +217,14 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { }; const getTaskIds = () => { - const taskIds = { completed: [], readyOrWaiting: [] }; + const taskIds: TaskIds = { completed: [], readyOrWaiting: [] }; if (tasks) { tasks.forEach(function getUserTasksElement(task: Task) { if (task.state === 'COMPLETED') { - (taskIds.completed as any).push(task); + taskIds.completed.push(task); } if (task.state === 'READY' || task.state === 'WAITING') { - (taskIds.readyOrWaiting as any).push(task); + taskIds.readyOrWaiting.push(task); } return null; }); @@ -230,20 +232,14 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { return taskIds; }; - const currentSpiffStep = () => { - if (processInstance && typeof params.to_task_guid === 'undefined') { - return processInstance.spiff_step || 0; - } - - return Number(params.spiff_step); - }; - - const showingFirstSpiffStep = () => { - return currentSpiffStep() === 1; + const currentToTaskGuid = () => { + return params.to_task_guid; }; const showingLastSpiffStep = () => { - return processInstance && currentSpiffStep() === processInstance.spiff_step; + return ( + processInstance && currentToTaskGuid() === processInstance.spiff_step + ); }; const completionViewLink = (label: any, taskGuid: string) => { @@ -278,7 +274,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { const resetProcessInstance = () => { HttpService.makeCallToBackend({ - path: `${targetUris.processInstanceResetPath}/${currentSpiffStep()}`, + path: `${targetUris.processInstanceResetPath}/${currentToTaskGuid()}`, successCallback: returnToLastSpiffStep, httpMethod: 'POST', }); @@ -580,7 +576,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { const getTaskById = (taskId: string) => { if (tasks !== null) { - return tasks.find((task: any) => task.id === taskId); + return tasks.find((task: Task) => task.guid === taskId) || null; } return null; }; @@ -589,24 +585,29 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { console.log('result', result); }; + const getParentTaskFromTask = (task: Task) => { + return task.properties_json.parent; + }; + const createScriptUnitTest = () => { if (taskToDisplay) { - const taskToUse: any = taskToDisplay; - const previousTask: any = getTaskById(taskToUse.parent); + const previousTask: Task | null = getTaskById( + getParentTaskFromTask(taskToDisplay) + ); HttpService.makeCallToBackend({ path: `/process-models/${modifiedProcessModelId}/script-unit-tests`, httpMethod: 'POST', successCallback: processScriptUnitTestCreateResult, postBody: { - bpmn_task_identifier: taskToUse.bpmn_identifier, - input_json: previousTask.data, - expected_output_json: taskToUse.data, + bpmn_task_identifier: taskToDisplay.bpmn_identifier, + input_json: previousTask ? previousTask.data : '', + expected_output_json: taskToDisplay.data, }, }); } }; - const isCurrentTask = (task: any) => { + const isCurrentTask = (task: Task) => { const subprocessTypes = [ 'Subprocess', 'Call Activity', @@ -619,7 +620,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { ); }; - const canEditTaskData = (task: any) => { + const canEditTaskData = (task: Task) => { return ( processInstance && ability.can('PUT', targetUris.processInstanceTaskDataPath) && @@ -629,7 +630,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { ); }; - const canSendEvent = (task: any) => { + const canSendEvent = (task: Task) => { // We actually could allow this for any waiting events const taskTypes = ['Event Based Gateway']; return ( @@ -642,7 +643,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { ); }; - const canCompleteTask = (task: any) => { + const canCompleteTask = (task: Task) => { return ( processInstance && processInstance.status === 'suspended' && @@ -652,7 +653,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { ); }; - const canResetProcess = (task: any) => { + const canResetProcess = (task: Task) => { return ( ability.can('POST', targetUris.processInstanceResetPath) && processInstance && @@ -662,8 +663,8 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { ); }; - const getEvents = (task: any) => { - const handleMessage = (eventDefinition: any) => { + const getEvents = (task: Task) => { + const handleMessage = (eventDefinition: EventDefinition) => { if (eventDefinition.typename === 'MessageEventDefinition') { const newEvent = eventDefinition; delete newEvent.message_var; @@ -673,7 +674,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { return eventDefinition; }; if (task.event_definition && task.event_definition.event_definitions) - return task.event_definition.event_definitions.map((e: any) => + return task.event_definition.event_definitions.map((e: EventDefinition) => handleMessage(e) ); if (task.event_definition) return [handleMessage(task.event_definition)]; @@ -710,11 +711,10 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { if (!taskToDisplay) { return; } - console.log('saveTaskData'); removeError(); // taskToUse is copy of taskToDisplay, with taskDataToDisplay in data attribute - const taskToUse: any = { ...taskToDisplay, data: taskDataToDisplay }; + const taskToUse: Task = { ...taskToDisplay, data: taskDataToDisplay }; HttpService.makeCallToBackend({ path: `${targetUris.processInstanceTaskDataPath}/${taskToUse.id}`, httpMethod: 'PUT', @@ -739,13 +739,14 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { }; const completeTask = (execute: boolean) => { - const taskToUse: any = taskToDisplay; - HttpService.makeCallToBackend({ - path: `/task-complete/${modifiedProcessModelId}/${params.process_instance_id}/${taskToUse.id}`, - httpMethod: 'POST', - successCallback: returnToLastSpiffStep, - postBody: { execute }, - }); + if (taskToDisplay) { + HttpService.makeCallToBackend({ + path: `/task-complete/${modifiedProcessModelId}/${params.process_instance_id}/${taskToDisplay.guid}`, + httpMethod: 'POST', + successCallback: returnToLastSpiffStep, + postBody: { execute }, + }); + } }; const taskDisplayButtons = (task: Task) => {