only return the compiled report metadata to the frontend and remove most usages of the internal filters w/ burnettk

This commit is contained in:
jasquat 2023-04-28 15:42:35 -04:00
parent b01b398287
commit 1f17e58a07
3 changed files with 64 additions and 48 deletions

View File

@ -163,6 +163,11 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel):
def terminal_statuses(cls) -> list[str]: def terminal_statuses(cls) -> list[str]:
return ["complete", "error", "terminated"] return ["complete", "error", "terminated"]
@classmethod
def non_terminal_statuses(cls) -> list[str]:
terminal_status_values = cls.terminal_statuses()
return [s for s in ProcessInstanceStatus.list() if s not in terminal_status_values]
@classmethod @classmethod
def active_statuses(cls) -> list[str]: def active_statuses(cls) -> list[str]:
return ["user_input_required", "waiting"] return ["user_input_required", "waiting"]

View File

@ -1,5 +1,6 @@
"""Process_instance_report_service.""" """Process_instance_report_service."""
import re import re
import copy
from typing import Any from typing import Any
from typing import Generator from typing import Generator
from typing import Optional from typing import Optional
@ -41,8 +42,10 @@ class ProcessInstanceReportService:
@classmethod @classmethod
def system_metadata_map(cls, metadata_key: str) -> Optional[ReportMetadata]: def system_metadata_map(cls, metadata_key: str) -> Optional[ReportMetadata]:
"""System_metadata_map."""
# TODO replace with system reports that are loaded on launch (or similar) # TODO replace with system reports that are loaded on launch (or similar)
terminal_status_values = ','.join(ProcessInstanceModel.terminal_statuses())
non_terminal_status_values = ','.join(ProcessInstanceModel.non_terminal_statuses())
active_status_values = ','.join(ProcessInstanceModel.active_statuses())
default: ReportMetadata = { default: ReportMetadata = {
"columns": cls.builtin_column_options(), "columns": cls.builtin_column_options(),
"filter_by": [], "filter_by": [],
@ -61,7 +64,7 @@ class ProcessInstanceReportService:
], ],
"filter_by": [ "filter_by": [
{"field_name": "initiated_by_me", "field_value": True}, {"field_name": "initiated_by_me", "field_value": True},
{"field_name": "has_terminal_status", "field_value": True}, {"field_name": "process_status", "field_value": terminal_status_values},
], ],
"order_by": ["-start_in_seconds", "-id"], "order_by": ["-start_in_seconds", "-id"],
} }
@ -69,18 +72,14 @@ class ProcessInstanceReportService:
"columns": cls.builtin_column_options(), "columns": cls.builtin_column_options(),
"filter_by": [ "filter_by": [
{"field_name": "with_tasks_completed_by_me", "field_value": True}, {"field_name": "with_tasks_completed_by_me", "field_value": True},
{"field_name": "has_terminal_status", "field_value": True}, {"field_name": "process_status", "field_value": terminal_status_values},
], ],
"order_by": ["-start_in_seconds", "-id"], "order_by": ["-start_in_seconds", "-id"],
} }
system_report_completed_instances_with_tasks_completed_by_my_groups: ReportMetadata = { system_report_completed_instances_with_tasks_completed_by_my_groups: ReportMetadata = {
"columns": cls.builtin_column_options(), "columns": cls.builtin_column_options(),
"filter_by": [ "filter_by": [
{ {"field_name": "process_status", "field_value": terminal_status_values},
"field_name": "with_tasks_assigned_to_my_group",
"field_value": True,
},
{"field_name": "has_terminal_status", "field_value": True},
], ],
"order_by": ["-start_in_seconds", "-id"], "order_by": ["-start_in_seconds", "-id"],
} }
@ -99,12 +98,10 @@ class ProcessInstanceReportService:
], ],
"filter_by": [ "filter_by": [
{"field_name": "initiated_by_me", "field_value": True}, {"field_name": "initiated_by_me", "field_value": True},
{"field_name": "has_terminal_status", "field_value": False}, {"field_name": "process_status", "field_value": non_terminal_status_values},
{ {
"field_name": "oldest_open_human_task_fields", "field_name": "with_oldest_open_task",
"field_value": ( "field_value": True,
"task_id,task_title,task_name,potential_owner_usernames,assigned_user_group_identifier"
),
}, },
], ],
"order_by": ["-start_in_seconds", "-id"], "order_by": ["-start_in_seconds", "-id"],
@ -123,10 +120,10 @@ class ProcessInstanceReportService:
], ],
"filter_by": [ "filter_by": [
{"field_name": "with_tasks_i_can_complete", "field_value": True}, {"field_name": "with_tasks_i_can_complete", "field_value": True},
{"field_name": "has_active_status", "field_value": True}, {"field_name": "process_status", "field_value": active_status_values},
{ {
"field_name": "oldest_open_human_task_fields", "field_name": "with_oldest_open_task",
"field_value": "task_id,task_title,task_name", "field_value": True,
}, },
], ],
"order_by": ["-start_in_seconds", "-id"], "order_by": ["-start_in_seconds", "-id"],
@ -144,15 +141,11 @@ class ProcessInstanceReportService:
{"Header": "Last Updated", "accessor": "updated_at_in_seconds"}, {"Header": "Last Updated", "accessor": "updated_at_in_seconds"},
], ],
"filter_by": [ "filter_by": [
{"field_name": "process_status", "field_value": active_status_values},
{ {
"field_name": "with_tasks_assigned_to_my_group", "field_name": "with_oldest_open_task",
"field_value": True, "field_value": True,
}, },
{"field_name": "has_active_status", "field_value": True},
{
"field_name": "oldest_open_human_task_fields",
"field_value": "task_id,task_title,task_name",
},
], ],
"order_by": ["-start_in_seconds", "-id"], "order_by": ["-start_in_seconds", "-id"],
} }
@ -178,6 +171,18 @@ class ProcessInstanceReportService:
return None return None
return temp_system_metadata_map[metadata_key] return temp_system_metadata_map[metadata_key]
@classmethod
def compile_report(cls, report_metadata: ReportMetadata, user: UserModel) -> None:
compiled_filters: list[FilterValue] = []
old_filters = copy.deepcopy(report_metadata['filter_by'])
for filter in old_filters:
if filter['field_name'] == 'initiated_by_me':
compiled_filters.append({'field_name': 'process_initiator_username', 'field_value': user.username})
else:
compiled_filters.append(filter)
report_metadata['filter_by'] = compiled_filters
@classmethod @classmethod
def report_with_identifier( def report_with_identifier(
cls, cls,
@ -206,6 +211,7 @@ class ProcessInstanceReportService:
raise ProcessInstanceReportNotFoundError( raise ProcessInstanceReportNotFoundError(
f"Could not find a report with identifier '{report_identifier}' for user '{user.username}'" f"Could not find a report with identifier '{report_identifier}' for user '{user.username}'"
) )
cls.compile_report(report_metadata, user=user)
process_instance_report = ProcessInstanceReportModel( process_instance_report = ProcessInstanceReportModel(
identifier=report_identifier, identifier=report_identifier,
@ -238,8 +244,9 @@ class ProcessInstanceReportService:
@classmethod @classmethod
def add_human_task_fields( def add_human_task_fields(
cls, process_instance_dicts: list[dict], oldest_open_human_task_fields: list cls, process_instance_dicts: list[dict]
) -> list[dict]: ) -> list[dict]:
fields_to_return = ["task_id", "task_title", "task_name", "potential_owner_usernames", "assigned_user_group_identifier"]
for process_instance_dict in process_instance_dicts: for process_instance_dict in process_instance_dicts:
assigned_user = aliased(UserModel) assigned_user = aliased(UserModel)
human_task_query = ( human_task_query = (
@ -265,7 +272,7 @@ class ProcessInstanceReportService:
.first() .first()
) )
if human_task is not None: if human_task is not None:
for field in oldest_open_human_task_fields: for field in fields_to_return:
process_instance_dict[field] = getattr(human_task, field) process_instance_dict[field] = getattr(human_task, field)
return process_instance_dicts return process_instance_dicts
@ -378,25 +385,18 @@ class ProcessInstanceReportService:
process_instance_query = process_instance_query.filter(ProcessInstanceModel.end_in_seconds >= value) process_instance_query = process_instance_query.filter(ProcessInstanceModel.end_in_seconds >= value)
for value in cls.check_filter_value(filters, "end_to"): for value in cls.check_filter_value(filters, "end_to"):
process_instance_query = process_instance_query.filter(ProcessInstanceModel.end_in_seconds <= value) process_instance_query = process_instance_query.filter(ProcessInstanceModel.end_in_seconds <= value)
for value in cls.check_filter_value(filters, "process_status"):
process_status = cls.get_filter_value(filters, "process_status")
if process_status is not None:
process_instance_query = process_instance_query.filter( process_instance_query = process_instance_query.filter(
ProcessInstanceModel.status.in_(value.split(",")) # type: ignore ProcessInstanceModel.status.in_(process_status.split(",")) # type: ignore
) )
for value in cls.check_filter_value(filters, "initiated_by_me"): for _value in cls.check_filter_value(filters, "initiated_by_me"):
if value is True: raise Exception("DEPRECATED: initiated_by_me")
# process_instance_query = process_instance_query.filter_by(process_initiator=user)
cls.add_or_update_filter(filters, {'field_name': 'process_initiator_username', 'field_value': user.username})
for value in cls.check_filter_value(filters, "has_terminal_status"): for value in cls.check_filter_value(filters, "has_terminal_status"):
if value is True: raise Exception("DEPRECATED: has_terminal_status")
process_instance_query = process_instance_query.filter(
ProcessInstanceModel.status.in_(ProcessInstanceModel.terminal_statuses()) # type: ignore
)
elif value is False:
process_instance_query = process_instance_query.filter(
ProcessInstanceModel.status.not_in(ProcessInstanceModel.terminal_statuses()) # type: ignore
)
has_active_status = cls.get_filter_value(filters, "has_active_status") has_active_status = cls.get_filter_value(filters, "has_active_status")
if has_active_status: if has_active_status:
@ -412,12 +412,15 @@ class ProcessInstanceReportService:
process_instance_query = process_instance_query.filter_by(process_initiator_id=process_initiator_id) process_instance_query = process_instance_query.filter_by(process_initiator_id=process_initiator_id)
with_tasks_completed_by_me = cls.get_filter_value(filters, "with_tasks_completed_by_me") with_tasks_completed_by_me = cls.get_filter_value(filters, "with_tasks_completed_by_me")
with_tasks_assigned_to_my_group = cls.get_filter_value(filters, "with_tasks_assigned_to_my_group")
with_tasks_i_can_complete = cls.get_filter_value(filters, "with_tasks_i_can_complete") with_tasks_i_can_complete = cls.get_filter_value(filters, "with_tasks_i_can_complete")
user_group_identifier = cls.get_filter_value(filters, "user_group_identifier")
# builtin only - for the for-me paths
with_relation_to_me = cls.get_filter_value(filters, "with_relation_to_me") with_relation_to_me = cls.get_filter_value(filters, "with_relation_to_me")
if ( if (
not with_tasks_completed_by_me not with_tasks_completed_by_me
and not with_tasks_assigned_to_my_group and not user_group_identifier
and not with_tasks_i_can_complete and not with_tasks_i_can_complete
and with_relation_to_me is True and with_relation_to_me is True
): ):
@ -465,17 +468,18 @@ class ProcessInstanceReportService:
and_(HumanTaskUserModel.human_task_id == HumanTaskModel.id, HumanTaskUserModel.user_id == user.id), and_(HumanTaskUserModel.human_task_id == HumanTaskModel.id, HumanTaskUserModel.user_id == user.id),
) )
if with_tasks_assigned_to_my_group is True: if user_group_identifier is not None:
user_group_identifier = cls.get_filter_value(filters, "user_group_identifier")
group_model_join_conditions = [GroupModel.id == HumanTaskModel.lane_assignment_id] group_model_join_conditions = [GroupModel.id == HumanTaskModel.lane_assignment_id]
if user_group_identifier: if user_group_identifier:
group_model_join_conditions.append(GroupModel.identifier == user_group_identifier) group_model_join_conditions.append(GroupModel.identifier == user_group_identifier)
process_instance_query = process_instance_query.join(HumanTaskModel) process_instance_query = process_instance_query.join(HumanTaskModel)
if has_active_status: if process_status is not None:
process_instance_query = process_instance_query.filter( non_active_statuses = [s for s in process_status.split(',') if s not in ProcessInstanceModel.active_statuses()]
HumanTaskModel.completed.is_(False) # type: ignore if len(non_active_statuses) == 0:
) process_instance_query = process_instance_query.filter(
HumanTaskModel.completed.is_(False) # type: ignore
)
process_instance_query = process_instance_query.join(GroupModel, and_(*group_model_join_conditions)) process_instance_query = process_instance_query.join(GroupModel, and_(*group_model_join_conditions))
process_instance_query = process_instance_query.join( process_instance_query = process_instance_query.join(
@ -537,8 +541,10 @@ class ProcessInstanceReportService:
) )
results = cls.add_metadata_columns_to_process_instance(process_instances.items, report_metadata["columns"]) results = cls.add_metadata_columns_to_process_instance(process_instances.items, report_metadata["columns"])
for value in cls.check_filter_value(filters, "oldest_open_human_task_fields"): for value in cls.check_filter_value(filters, "with_oldest_open_task"):
results = cls.add_human_task_fields(results, value.split(",")) if value is True:
results = cls.add_human_task_fields(results)
report_metadata['filter_by'] = filters report_metadata['filter_by'] = filters
response_json = { response_json = {
"report_metadata": report_metadata, "report_metadata": report_metadata,

View File

@ -1,3 +1,8 @@
// TODO:
// add drop down for user_group_identifier and one for the 2 system reports:
// with_tasks_completed_by_me
// with_tasks_i_can_complete
// add checkbox to show with_oldest_open_task
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { import {
Link, Link,