Merge branch 'main' of github.com:sartography/spiff-arena

This commit is contained in:
jasquat 2022-11-22 17:23:01 -05:00
commit ee61e43237
6 changed files with 197 additions and 15 deletions

View File

@ -514,6 +514,24 @@ paths:
description: For filtering - not_started, user_input_required, waiting, complete, error, or suspended
schema:
type: string
- name: initiated_by_me
in: query
required: false
description: For filtering - show instances initiated by me
schema:
type: boolean
- name: with_tasks_completed_by_me
in: query
required: false
description: For filtering - show instances with tasks completed by me
schema:
type: boolean
- name: with_tasks_completed_by_my_group
in: query
required: false
description: For filtering - show instances with tasks completed by my group
schema:
type: boolean
- name: user_filter
in: query
required: false

View File

@ -30,6 +30,7 @@ from SpiffWorkflow.task import TaskState
from sqlalchemy import and_
from sqlalchemy import asc
from sqlalchemy import desc
from sqlalchemy import select
from spiffworkflow_backend.exceptions.process_entity_not_found_error import (
ProcessEntityNotFoundError,
@ -63,6 +64,7 @@ from spiffworkflow_backend.models.spec_reference import SpecReferenceSchema
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel
from spiffworkflow_backend.models.user import UserModel
from spiffworkflow_backend.models.user_group_assignment import UserGroupAssignmentModel
from spiffworkflow_backend.routes.user import verify_token
from spiffworkflow_backend.services.authorization_service import AuthorizationService
from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService
@ -762,6 +764,9 @@ def process_instance_list(
end_from: Optional[int] = None,
end_to: Optional[int] = None,
process_status: Optional[str] = None,
initiated_by_me: Optional[bool] = None,
with_tasks_completed_by_me: Optional[bool] = None,
with_tasks_completed_by_my_group: Optional[bool] = None,
user_filter: Optional[bool] = False,
report_identifier: Optional[str] = None,
) -> flask.wrappers.Response:
@ -778,6 +783,9 @@ def process_instance_list(
end_from,
end_to,
process_status.split(",") if process_status else None,
initiated_by_me,
with_tasks_completed_by_me,
with_tasks_completed_by_my_group,
)
else:
report_filter = (
@ -789,6 +797,9 @@ def process_instance_list(
end_from,
end_to,
process_status,
initiated_by_me,
with_tasks_completed_by_me,
with_tasks_completed_by_my_group,
)
)
@ -837,9 +848,79 @@ def process_instance_list(
ProcessInstanceModel.status.in_(report_filter.process_status) # type: ignore
)
process_instances = process_instance_query.order_by(
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore
).paginate(page=page, per_page=per_page, error_out=False)
if report_filter.initiated_by_me is True:
process_instance_query = process_instance_query.filter(
ProcessInstanceModel.status == "complete"
)
process_instance_query = process_instance_query.filter_by(
process_initiator=g.user
)
# TODO: not sure if this is exactly what is wanted
if report_filter.with_tasks_completed_by_me is True:
process_instance_query = process_instance_query.filter(
ProcessInstanceModel.status == "complete"
)
process_instance_query = process_instance_query.join(
SpiffStepDetailsModel,
ProcessInstanceModel.id == SpiffStepDetailsModel.process_instance_id,
)
process_instance_query = process_instance_query.join(
SpiffLoggingModel,
ProcessInstanceModel.id == SpiffLoggingModel.process_instance_id,
)
process_instance_query = process_instance_query.filter(
SpiffLoggingModel.message.contains("COMPLETED") # type: ignore
)
process_instance_query = process_instance_query.filter(
SpiffLoggingModel.spiff_step == SpiffStepDetailsModel.spiff_step
)
process_instance_query = process_instance_query.filter(
SpiffStepDetailsModel.completed_by_user_id == g.user.id
)
# TODO: not sure if this is exactly what is wanted
if report_filter.with_tasks_completed_by_my_group is True:
process_instance_query = process_instance_query.filter(
ProcessInstanceModel.status == "complete"
)
process_instance_query = process_instance_query.join(
SpiffStepDetailsModel,
ProcessInstanceModel.id == SpiffStepDetailsModel.process_instance_id,
)
process_instance_query = process_instance_query.join(
SpiffLoggingModel,
ProcessInstanceModel.id == SpiffLoggingModel.process_instance_id,
)
process_instance_query = process_instance_query.filter(
SpiffLoggingModel.message.contains("COMPLETED") # type: ignore
)
process_instance_query = process_instance_query.filter(
SpiffLoggingModel.spiff_step == SpiffStepDetailsModel.spiff_step
)
my_groups = (
select(UserGroupAssignmentModel) # type: ignore
.where(UserGroupAssignmentModel.user_id == g.user.id)
.with_only_columns(UserGroupAssignmentModel.group_id)
)
users_in_my_groups = (
select(UserGroupAssignmentModel) # type: ignore
.where(UserGroupAssignmentModel.group_id.in_(my_groups))
.with_only_columns(UserGroupAssignmentModel.user_id)
)
process_instance_query = process_instance_query.filter(
SpiffStepDetailsModel.completed_by_user_id.in_(users_in_my_groups) # type: ignore
)
process_instances = (
process_instance_query.distinct()
.order_by(
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore
)
.paginate(page=page, per_page=per_page, error_out=False)
)
results = list(
map(
@ -1005,7 +1086,7 @@ def authentication_callback(
f"{service}/{auth_method}", response, g.user.id, create_if_not_exists=True
)
return redirect(
f"{current_app.config['SPIFFWORKFLOW_FRONTEND_URL']}/admin/authentications"
f"{current_app.config['SPIFFWORKFLOW_FRONTEND_URL']}/admin/configuration"
)

View File

@ -18,6 +18,9 @@ class ProcessInstanceReportFilter:
end_from: Optional[int] = None
end_to: Optional[int] = None
process_status: Optional[list[str]] = None
initiated_by_me: Optional[bool] = None
with_tasks_completed_by_me: Optional[bool] = None
with_tasks_completed_by_my_group: Optional[bool] = None
def to_dict(self) -> dict[str, str]:
"""To_dict."""
@ -35,6 +38,16 @@ class ProcessInstanceReportFilter:
d["end_to"] = str(self.end_to)
if self.process_status is not None:
d["process_status"] = ",".join(self.process_status)
if self.initiated_by_me is not None:
d["initiated_by_me"] = str(self.initiated_by_me).lower()
if self.with_tasks_completed_by_me is not None:
d["with_tasks_completed_by_me"] = str(
self.with_tasks_completed_by_me
).lower()
if self.with_tasks_completed_by_my_group is not None:
d["with_tasks_completed_by_my_group"] = str(
self.with_tasks_completed_by_my_group
).lower()
return d
@ -73,30 +86,35 @@ class ProcessInstanceReportService:
},
"system_report_instances_initiated_by_me": {
"columns": [
{"Header": "id", "accessor": "id"},
{
"Header": "process_model_identifier",
"accessor": "process_model_identifier",
},
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
{"Header": "id", "accessor": "id"},
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
{"Header": "status", "accessor": "status"},
],
"filter_by": [{"field_name": "initiated_by_me", "field_value": True}],
},
"system_report_instances_with_tasks_completed_by_me": {
"columns": [
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
{"Header": "status", "accessor": "status"},
{"Header": "id", "accessor": "id"},
{
"Header": "process_model_identifier",
"accessor": "process_model_identifier",
},
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
{"Header": "status", "accessor": "status"},
],
"filter_by": [
{"field_name": "with_tasks_completed_by_me", "field_value": True}
],
},
"system_report_instances_with_tasks_completed_by_my_groups": {
"columns": [
{"Header": "id", "accessor": "id"},
{
"Header": "process_model_identifier",
"accessor": "process_model_identifier",
@ -104,7 +122,12 @@ class ProcessInstanceReportService:
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
{"Header": "status", "accessor": "status"},
{"Header": "id", "accessor": "id"},
],
"filter_by": [
{
"field_name": "with_tasks_completed_by_my_group",
"field_value": True,
}
],
},
}
@ -112,7 +135,7 @@ class ProcessInstanceReportService:
process_instance_report = ProcessInstanceReportModel(
identifier=report_identifier,
created_by_id=user.id,
report_metadata=temp_system_metadata_map[report_identifier],
report_metadata=temp_system_metadata_map[report_identifier], # type: ignore
)
return process_instance_report # type: ignore
@ -138,6 +161,10 @@ class ProcessInstanceReportService:
"""Filter_from_metadata."""
filters = cls.filter_by_to_dict(process_instance_report)
def bool_value(key: str) -> Optional[bool]:
"""Bool_value."""
return bool(filters[key]) if key in filters else None
def int_value(key: str) -> Optional[int]:
"""Int_value."""
return int(filters[key]) if key in filters else None
@ -152,6 +179,11 @@ class ProcessInstanceReportService:
end_from = int_value("end_from")
end_to = int_value("end_to")
process_status = list_value("process_status")
initiated_by_me = bool_value("initiated_by_me")
with_tasks_completed_by_me = bool_value("with_tasks_completed_by_me")
with_tasks_completed_by_my_group = bool_value(
"with_tasks_completed_by_my_group"
)
report_filter = ProcessInstanceReportFilter(
process_model_identifier,
@ -160,6 +192,9 @@ class ProcessInstanceReportService:
end_from,
end_to,
process_status,
initiated_by_me,
with_tasks_completed_by_me,
with_tasks_completed_by_my_group,
)
return report_filter
@ -174,6 +209,9 @@ class ProcessInstanceReportService:
end_from: Optional[int] = None,
end_to: Optional[int] = None,
process_status: Optional[str] = None,
initiated_by_me: Optional[bool] = None,
with_tasks_completed_by_me: Optional[bool] = None,
with_tasks_completed_by_my_group: Optional[bool] = None,
) -> ProcessInstanceReportFilter:
"""Filter_from_metadata_with_overrides."""
report_filter = cls.filter_from_metadata(process_instance_report)
@ -190,5 +228,13 @@ class ProcessInstanceReportService:
report_filter.end_to = end_to
if process_status is not None:
report_filter.process_status = process_status.split(",")
if initiated_by_me is not None:
report_filter.initiated_by_me = initiated_by_me
if with_tasks_completed_by_me is not None:
report_filter.with_tasks_completed_by_me = with_tasks_completed_by_me
if with_tasks_completed_by_my_group is not None:
report_filter.with_tasks_completed_by_my_group = (
with_tasks_completed_by_my_group
)
return report_filter

View File

@ -8,6 +8,8 @@ export default function MyCompletedInstances() {
filtersEnabled={false}
paginationQueryParamPrefix={paginationQueryParamPrefix}
perPageOptions={[2, 5, 25]}
reportIdentifier="system_report_instances_initiated_by_me"
showReports={false}
/>
);
}

View File

@ -57,6 +57,7 @@ type OwnProps = {
paginationQueryParamPrefix?: string;
perPageOptions?: number[];
showReports?: boolean;
reportIdentifier?: string;
};
interface dateParameters {
@ -69,6 +70,7 @@ export default function ProcessInstanceListTable({
paginationQueryParamPrefix,
perPageOptions,
showReports = true,
reportIdentifier,
}: OwnProps) {
const params = useParams();
const [searchParams] = useSearchParams();
@ -173,9 +175,14 @@ export default function ProcessInstanceListTable({
queryParamString += `&user_filter=${userAppliedFilter}`;
}
const reportIdentifier = searchParams.get('report_identifier');
if (reportIdentifier) {
queryParamString += `&report_identifier=${reportIdentifier}`;
let reportIdentifierToUse: any = reportIdentifier;
if (!reportIdentifierToUse) {
reportIdentifierToUse = searchParams.get('report_identifier');
}
if (reportIdentifierToUse) {
queryParamString += `&report_identifier=${reportIdentifierToUse}`;
}
Object.keys(dateParametersToAlwaysFilterBy).forEach(
@ -273,6 +280,7 @@ export default function ProcessInstanceListTable({
paginationQueryParamPrefix,
processModelFullIdentifier,
perPageOptions,
reportIdentifier,
]);
// This sets the filter data using the saved reports returned from the initial instance_list query.

View File

@ -1,5 +1,32 @@
import MyCompletedInstances from '../components/MyCompletedInstances';
import ProcessInstanceListTable from '../components/ProcessInstanceListTable';
export default function CompletedInstances() {
return <MyCompletedInstances />;
return (
<>
<h1>Initiated By Me</h1>
<ProcessInstanceListTable
filtersEnabled={false}
paginationQueryParamPrefix="my_completed_instances"
perPageOptions={[2, 5, 25]}
reportIdentifier="system_report_instances_initiated_by_me"
showReports={false}
/>
<h1 style={{ marginTop: '1em' }}>With Tasks Completed By Me</h1>
<ProcessInstanceListTable
filtersEnabled={false}
paginationQueryParamPrefix="my_completed_tasks"
perPageOptions={[2, 5, 25]}
reportIdentifier="system_report_instances_with_tasks_completed_by_me"
showReports={false}
/>
<h1 style={{ marginTop: '1em' }}>With Tasks Completed By My Group</h1>
<ProcessInstanceListTable
filtersEnabled={false}
paginationQueryParamPrefix="group_completed_tasks"
perPageOptions={[2, 5, 25]}
reportIdentifier="system_report_instances_with_tasks_completed_by_my_groups"
showReports={false}
/>
</>
);
}