diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py index 673834f8..ab1de98d 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py @@ -422,7 +422,7 @@ class ProcessInstanceReportService: for process_instance_dict in process_instance_dicts: assigned_user = aliased(UserModel) human_task_query = ( - HumanTaskModel.query.filter_by(process_instance_id=process_instance_dict['id']) + HumanTaskModel.query.filter_by(process_instance_id=process_instance_dict['id'], completed=False) .group_by(HumanTaskModel.id) .outerjoin( HumanTaskUserModel, diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 0dcc6398..f193f0e8 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -1303,6 +1303,111 @@ export default function ProcessInstanceListTable({ ); }; + const getWaitingForTableCellComponent = (processInstanceTask: any) => { + let fullUsernameString = ''; + let shortUsernameString = ''; + if (processInstanceTask.potential_owner_usernames) { + fullUsernameString = processInstanceTask.potential_owner_usernames; + const usernames = + processInstanceTask.potential_owner_usernames.split(','); + const firstTwoUsernames = usernames.slice(0, 2); + if (usernames.length > 2) { + firstTwoUsernames.push('...'); + } + shortUsernameString = firstTwoUsernames.join(','); + } + if (processInstanceTask.assigned_user_group_identifier) { + fullUsernameString = processInstanceTask.assigned_user_group_identifier; + shortUsernameString = processInstanceTask.assigned_user_group_identifier; + } + return {shortUsernameString}; + }; + const formatProcessInstanceId = (row: ProcessInstance, id: number) => { + return {id}; + }; + const formatProcessModelIdentifier = (_row: any, identifier: any) => { + return {identifier}; + }; + const formatProcessModelDisplayName = (_row: any, identifier: any) => { + return {identifier}; + }; + + const formatSecondsForDisplay = (_row: any, seconds: any) => { + return convertSecondsToFormattedDateTime(seconds) || '-'; + }; + const defaultFormatter = (_row: any, value: any) => { + return value; + }; + + const formattedColumn = (row: any, column: any) => { + const reportColumnFormatters: Record = { + id: formatProcessInstanceId, + process_model_identifier: formatProcessModelIdentifier, + process_model_display_name: formatProcessModelDisplayName, + start_in_seconds: formatSecondsForDisplay, + end_in_seconds: formatSecondsForDisplay, + updated_at_in_seconds: formatSecondsForDisplay, + }; + const formatter = + reportColumnFormatters[column.accessor] ?? defaultFormatter; + const value = row[column.accessor]; + const modifiedModelId = modifyProcessIdentifierForPathParam( + row.process_model_identifier + ); + const navigateToProcessInstance = () => { + navigate(`${processInstanceShowPathPrefix}/${modifiedModelId}/${row.id}`); + }; + const navigateToProcessModel = () => { + navigate(`/admin/process-models/${modifiedModelId}`); + }; + + if (column.accessor === 'status') { + return ( + // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions + + {formatter(row, value)} + + ); + } + if (column.accessor === 'process_model_display_name') { + const pmStyle = { background: 'rgba(0, 0, 0, .02)' }; + return ( + // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions + + {formatter(row, value)} + + ); + } + if (column.accessor === 'waiting_for') { + return {getWaitingForTableCellComponent(row)}; + } + if (column.accessor === 'updated_at_in_seconds') { + return ( + + ); + } + return ( + // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions + + {formatter(row, value)} + + ); + }; + const buildTable = () => { const headerLabels: Record = { id: 'Id', @@ -1323,115 +1428,6 @@ export default function ProcessInstanceListTable({ headers.push('Actions'); } - const formatProcessInstanceId = (row: ProcessInstance, id: number) => { - return {id}; - }; - const formatProcessModelIdentifier = (_row: any, identifier: any) => { - return {identifier}; - }; - const formatProcessModelDisplayName = (_row: any, identifier: any) => { - return {identifier}; - }; - - const formatSecondsForDisplay = (_row: any, seconds: any) => { - return convertSecondsToFormattedDateTime(seconds) || '-'; - }; - const defaultFormatter = (_row: any, value: any) => { - return value; - }; - - const getWaitingForTableCellComponent = (processInstanceTask: any) => { - let fullUsernameString = ''; - let shortUsernameString = ''; - if (processInstanceTask.potential_owner_usernames) { - fullUsernameString = processInstanceTask.potential_owner_usernames; - const usernames = - processInstanceTask.potential_owner_usernames.split(','); - const firstTwoUsernames = usernames.slice(0, 2); - if (usernames.length > 2) { - firstTwoUsernames.push('...'); - } - shortUsernameString = firstTwoUsernames.join(','); - } - if (processInstanceTask.assigned_user_group_identifier) { - fullUsernameString = processInstanceTask.assigned_user_group_identifier; - shortUsernameString = - processInstanceTask.assigned_user_group_identifier; - } - return {shortUsernameString}; - }; - - const reportColumnFormatters: Record = { - id: formatProcessInstanceId, - process_model_identifier: formatProcessModelIdentifier, - process_model_display_name: formatProcessModelDisplayName, - start_in_seconds: formatSecondsForDisplay, - end_in_seconds: formatSecondsForDisplay, - updated_at_in_seconds: formatSecondsForDisplay, - }; - const formattedColumn = (row: any, column: any) => { - const formatter = - reportColumnFormatters[column.accessor] ?? defaultFormatter; - const value = row[column.accessor]; - const modifiedModelId = modifyProcessIdentifierForPathParam( - row.process_model_identifier - ); - const navigateToProcessInstance = () => { - navigate( - `${processInstanceShowPathPrefix}/${modifiedModelId}/${row.id}` - ); - }; - const navigateToProcessModel = () => { - navigate(`/admin/process-models/${modifiedModelId}`); - }; - - if (column.accessor === 'status') { - return ( - // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions - - {formatter(row, value)} - - ); - } - if (column.accessor === 'process_model_display_name') { - const pmStyle = { background: 'rgba(0, 0, 0, .02)' }; - return ( - // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions - - {formatter(row, value)} - - ); - } - if (column.accessor === 'waiting_for') { - return {getWaitingForTableCellComponent(row)}; - } - if (column.accessor === 'updated_at_in_seconds') { - return ( - - ); - } - return ( - // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions - - {formatter(row, value)} - - ); - }; - const rows = processInstances.map((row: any) => { const currentRow = reportColumns().map((column: any) => { return formattedColumn(row, column); diff --git a/spiffworkflow-frontend/src/index.css b/spiffworkflow-frontend/src/index.css index 07704036..e05c2847 100644 --- a/spiffworkflow-frontend/src/index.css +++ b/spiffworkflow-frontend/src/index.css @@ -332,10 +332,13 @@ td.actions-cell { width: 1em; } +.process-instance-table-header { + margin-bottom: 1em; +} + .no-results-message { font-style: italic; margin-left: 2em; - margin-top: 1em; font-size: 14px; } diff --git a/spiffworkflow-frontend/src/routes/CompletedInstances.tsx b/spiffworkflow-frontend/src/routes/CompletedInstances.tsx index 5c7ce445..78f73e92 100644 --- a/spiffworkflow-frontend/src/routes/CompletedInstances.tsx +++ b/spiffworkflow-frontend/src/routes/CompletedInstances.tsx @@ -18,13 +18,12 @@ export default function CompletedInstances() { } return userGroups.map((userGroup: string) => { + const titleText = `This is a list of instances with tasks that were completed by the ${userGroup} group.`; return ( <> -

With tasks completed by group: {userGroup}

-

- This is a list of instances with tasks that were completed by the{' '} - {userGroup} group. -

+

+ With tasks completed by {userGroup} +

-

My completed instances

-

- This is a list of instances you started that are now complete. -

+

+ Started by me +

-

With tasks completed by me

-

- This is a list of instances where you have completed tasks. -

+

+ With tasks completed by me +

{ + const titleText = `This is a list of instances with tasks that are waiting for the ${userGroup} group.`; return ( <> -

With tasks completed by group: {userGroup}

-

- This is a list of instances with tasks that were completed by the{' '} - {userGroup} group. -

+

+ Waiting for {userGroup} +

-

My open instances

-

- This is a list of instances you started that are now complete. -

+

+ Started by me +

-

With tasks I can complete

-

- This is a list of instances that have tasks that you can complete. -

+

+ Waiting for me +