added support to order reports by given column and metadata headers w/ burnettk
This commit is contained in:
parent
f920edbb56
commit
424eb2412e
|
@ -75,6 +75,10 @@ class ProcessInstanceReportModel(SpiffworkflowBaseDBModel):
|
||||||
created_at_in_seconds = db.Column(db.Integer)
|
created_at_in_seconds = db.Column(db.Integer)
|
||||||
updated_at_in_seconds = db.Column(db.Integer)
|
updated_at_in_seconds = db.Column(db.Integer)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_order_by(cls) -> list[str]:
|
||||||
|
return ["-start_in_seconds", "-id"]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_fixtures(cls) -> None:
|
def add_fixtures(cls) -> None:
|
||||||
"""Add_fixtures."""
|
"""Add_fixtures."""
|
||||||
|
|
|
@ -3,6 +3,7 @@ import json
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
import uuid
|
import uuid
|
||||||
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
@ -944,6 +945,7 @@ def process_instance_list(
|
||||||
UserGroupAssignmentModel.user_id == g.user.id
|
UserGroupAssignmentModel.user_id == g.user.id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
instance_metadata_aliases = {}
|
||||||
stock_columns = ProcessInstanceReportService.get_column_names_for_model(
|
stock_columns = ProcessInstanceReportService.get_column_names_for_model(
|
||||||
ProcessInstanceModel
|
ProcessInstanceModel
|
||||||
)
|
)
|
||||||
|
@ -951,15 +953,18 @@ def process_instance_list(
|
||||||
if column["accessor"] in stock_columns:
|
if column["accessor"] in stock_columns:
|
||||||
continue
|
continue
|
||||||
instance_metadata_alias = aliased(ProcessInstanceMetadataModel)
|
instance_metadata_alias = aliased(ProcessInstanceMetadataModel)
|
||||||
|
instance_metadata_aliases[column['accessor']] = instance_metadata_alias
|
||||||
|
|
||||||
filter_for_column = next(
|
filter_for_column = None
|
||||||
(
|
if 'filter_by' in process_instance_report.report_metadata:
|
||||||
f
|
filter_for_column = next(
|
||||||
for f in process_instance_report.report_metadata["filter_by"]
|
(
|
||||||
if f["field_name"] == column["accessor"]
|
f
|
||||||
),
|
for f in process_instance_report.report_metadata["filter_by"]
|
||||||
None,
|
if f["field_name"] == column["accessor"]
|
||||||
)
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
isouter = True
|
isouter = True
|
||||||
conditions = [
|
conditions = [
|
||||||
ProcessInstanceModel.id == instance_metadata_alias.process_instance_id,
|
ProcessInstanceModel.id == instance_metadata_alias.process_instance_id,
|
||||||
|
@ -974,11 +979,28 @@ def process_instance_list(
|
||||||
instance_metadata_alias, and_(*conditions), isouter=isouter
|
instance_metadata_alias, and_(*conditions), isouter=isouter
|
||||||
).add_columns(func.max(instance_metadata_alias.value).label(column["accessor"]))
|
).add_columns(func.max(instance_metadata_alias.value).label(column["accessor"]))
|
||||||
|
|
||||||
|
order_by_query_array = []
|
||||||
|
order_by_array = process_instance_report.report_metadata['order_by']
|
||||||
|
if len(order_by_array) < 1:
|
||||||
|
order_by_array = ProcessInstanceReportModel.default_order_by()
|
||||||
|
for order_by_option in order_by_array:
|
||||||
|
attribute = re.sub('^-', '', order_by_option)
|
||||||
|
if attribute in stock_columns:
|
||||||
|
if order_by_option.startswith('-'):
|
||||||
|
order_by_query_array.append(getattr(ProcessInstanceModel, attribute).desc())
|
||||||
|
else:
|
||||||
|
order_by_query_array.append(getattr(ProcessInstanceModel, attribute).asc())
|
||||||
|
elif attribute in instance_metadata_aliases:
|
||||||
|
if order_by_option.startswith('-'):
|
||||||
|
order_by_query_array.append(instance_metadata_aliases[attribute].value.desc())
|
||||||
|
else:
|
||||||
|
order_by_query_array.append(instance_metadata_aliases[attribute].value.asc())
|
||||||
|
|
||||||
process_instances = (
|
process_instances = (
|
||||||
process_instance_query.group_by(ProcessInstanceModel.id)
|
process_instance_query.group_by(ProcessInstanceModel.id)
|
||||||
.add_columns(ProcessInstanceModel.id)
|
.add_columns(ProcessInstanceModel.id)
|
||||||
.order_by(
|
.order_by(
|
||||||
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore
|
*order_by_query_array
|
||||||
)
|
)
|
||||||
.paginate(page=page, per_page=per_page, error_out=False)
|
.paginate(page=page, per_page=per_page, error_out=False)
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
<bpmn:outgoing>Flow_18gs4jt</bpmn:outgoing>
|
<bpmn:outgoing>Flow_18gs4jt</bpmn:outgoing>
|
||||||
<bpmn:script>outer = {}
|
<bpmn:script>outer = {}
|
||||||
invoice_number = 123
|
invoice_number = 123
|
||||||
outer["inner"] = 'sweet1'</bpmn:script>
|
outer["inner"] = 'sweet1'
|
||||||
|
outer['time'] = time.time_ns()</bpmn:script>
|
||||||
</bpmn:scriptTask>
|
</bpmn:scriptTask>
|
||||||
<bpmn:sequenceFlow id="Flow_1flxgry" sourceRef="Activity_1bvyv67" targetRef="Event_1tk4dsv" />
|
<bpmn:sequenceFlow id="Flow_1flxgry" sourceRef="Activity_1bvyv67" targetRef="Event_1tk4dsv" />
|
||||||
<bpmn:scriptTask id="Activity_1bvyv67" name="First setting of data">
|
<bpmn:scriptTask id="Activity_1bvyv67" name="First setting of data">
|
||||||
|
|
|
@ -2657,3 +2657,86 @@ class TestProcessApi(BaseTest):
|
||||||
{"Header": "key2", "accessor": "key2", "filterable": True},
|
{"Header": "key2", "accessor": "key2", "filterable": True},
|
||||||
{"Header": "key3", "accessor": "key3", "filterable": True},
|
{"Header": "key3", "accessor": "key3", "filterable": True},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def test_process_instance_list_can_order_by_metadata(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
client: FlaskClient,
|
||||||
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
|
with_super_admin_user: UserModel,
|
||||||
|
) -> None:
|
||||||
|
self.create_process_group(
|
||||||
|
client, with_super_admin_user, "test_group", "test_group"
|
||||||
|
)
|
||||||
|
process_model = load_test_spec(
|
||||||
|
"test_group/hello_world",
|
||||||
|
process_model_source_directory="nested-task-data-structure",
|
||||||
|
)
|
||||||
|
ProcessModelService.update_process_model(
|
||||||
|
process_model,
|
||||||
|
{
|
||||||
|
"metadata_extraction_paths": [
|
||||||
|
{"key": "time_ns", "path": "outer.time"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
process_instance_one = self.create_process_instance_from_process_model(
|
||||||
|
process_model
|
||||||
|
)
|
||||||
|
processor = ProcessInstanceProcessor(process_instance_one)
|
||||||
|
processor.do_engine_steps(save=True)
|
||||||
|
assert process_instance_one.status == "complete"
|
||||||
|
process_instance_two = self.create_process_instance_from_process_model(
|
||||||
|
process_model
|
||||||
|
)
|
||||||
|
processor = ProcessInstanceProcessor(process_instance_two)
|
||||||
|
processor.do_engine_steps(save=True)
|
||||||
|
assert process_instance_two.status == "complete"
|
||||||
|
|
||||||
|
report_metadata = {
|
||||||
|
"columns": [
|
||||||
|
{"Header": "id", "accessor": "id"},
|
||||||
|
{"Header": "Time", "accessor": "time_ns"},
|
||||||
|
],
|
||||||
|
"order_by": ["time_ns"],
|
||||||
|
}
|
||||||
|
report_one = ProcessInstanceReportModel.create_with_attributes(
|
||||||
|
identifier="report_one",
|
||||||
|
report_metadata=report_metadata,
|
||||||
|
user=with_super_admin_user,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f"/v1.0/process-instances?report_id={report_one.id}",
|
||||||
|
headers=self.logged_in_headers(with_super_admin_user),
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json is not None
|
||||||
|
assert len(response.json["results"]) == 2
|
||||||
|
assert response.json['results'][0]['id'] == process_instance_one.id
|
||||||
|
assert response.json['results'][1]['id'] == process_instance_two.id
|
||||||
|
|
||||||
|
report_metadata = {
|
||||||
|
"columns": [
|
||||||
|
{"Header": "id", "accessor": "id"},
|
||||||
|
{"Header": "Time", "accessor": "time_ns"},
|
||||||
|
],
|
||||||
|
"order_by": ["-time_ns"],
|
||||||
|
}
|
||||||
|
report_two = ProcessInstanceReportModel.create_with_attributes(
|
||||||
|
identifier="report_two",
|
||||||
|
report_metadata=report_metadata,
|
||||||
|
user=with_super_admin_user,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f"/v1.0/process-instances?report_id={report_two.id}",
|
||||||
|
headers=self.logged_in_headers(with_super_admin_user),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json is not None
|
||||||
|
assert len(response.json["results"]) == 2
|
||||||
|
assert response.json['results'][1]['id'] == process_instance_one.id
|
||||||
|
assert response.json['results'][0]['id'] == process_instance_two.id
|
||||||
|
|
Loading…
Reference in New Issue