Start of system report filters (#57)
This commit is contained in:
parent
8b562b0bf2
commit
ceefa9a2f7
|
@ -514,6 +514,24 @@ paths:
|
||||||
description: For filtering - not_started, user_input_required, waiting, complete, error, or suspended
|
description: For filtering - not_started, user_input_required, waiting, complete, error, or suspended
|
||||||
schema:
|
schema:
|
||||||
type: string
|
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
|
- name: user_filter
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
|
|
|
@ -30,6 +30,7 @@ from SpiffWorkflow.task import TaskState
|
||||||
from sqlalchemy import and_
|
from sqlalchemy import and_
|
||||||
from sqlalchemy import asc
|
from sqlalchemy import asc
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
|
from sqlalchemy import select
|
||||||
|
|
||||||
from spiffworkflow_backend.exceptions.process_entity_not_found_error import (
|
from spiffworkflow_backend.exceptions.process_entity_not_found_error import (
|
||||||
ProcessEntityNotFoundError,
|
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_logging import SpiffLoggingModel
|
||||||
from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel
|
from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel
|
||||||
from spiffworkflow_backend.models.user import UserModel
|
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.routes.user import verify_token
|
||||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||||
from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService
|
from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService
|
||||||
|
@ -762,6 +764,9 @@ def process_instance_list(
|
||||||
end_from: Optional[int] = None,
|
end_from: Optional[int] = None,
|
||||||
end_to: Optional[int] = None,
|
end_to: Optional[int] = None,
|
||||||
process_status: Optional[str] = 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,
|
user_filter: Optional[bool] = False,
|
||||||
report_identifier: Optional[str] = None,
|
report_identifier: Optional[str] = None,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
|
@ -778,6 +783,9 @@ def process_instance_list(
|
||||||
end_from,
|
end_from,
|
||||||
end_to,
|
end_to,
|
||||||
process_status.split(",") if process_status else None,
|
process_status.split(",") if process_status else None,
|
||||||
|
initiated_by_me,
|
||||||
|
with_tasks_completed_by_me,
|
||||||
|
with_tasks_completed_by_my_group,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
report_filter = (
|
report_filter = (
|
||||||
|
@ -789,6 +797,9 @@ def process_instance_list(
|
||||||
end_from,
|
end_from,
|
||||||
end_to,
|
end_to,
|
||||||
process_status,
|
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
|
ProcessInstanceModel.status.in_(report_filter.process_status) # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
process_instances = process_instance_query.order_by(
|
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
|
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore
|
||||||
).paginate(page=page, per_page=per_page, error_out=False)
|
)
|
||||||
|
.paginate(page=page, per_page=per_page, error_out=False)
|
||||||
|
)
|
||||||
|
|
||||||
results = list(
|
results = list(
|
||||||
map(
|
map(
|
||||||
|
|
|
@ -18,6 +18,9 @@ class ProcessInstanceReportFilter:
|
||||||
end_from: Optional[int] = None
|
end_from: Optional[int] = None
|
||||||
end_to: Optional[int] = None
|
end_to: Optional[int] = None
|
||||||
process_status: Optional[list[str]] = 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]:
|
def to_dict(self) -> dict[str, str]:
|
||||||
"""To_dict."""
|
"""To_dict."""
|
||||||
|
@ -35,6 +38,16 @@ class ProcessInstanceReportFilter:
|
||||||
d["end_to"] = str(self.end_to)
|
d["end_to"] = str(self.end_to)
|
||||||
if self.process_status is not None:
|
if self.process_status is not None:
|
||||||
d["process_status"] = ",".join(self.process_status)
|
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
|
return d
|
||||||
|
|
||||||
|
@ -73,30 +86,35 @@ class ProcessInstanceReportService:
|
||||||
},
|
},
|
||||||
"system_report_instances_initiated_by_me": {
|
"system_report_instances_initiated_by_me": {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
{"Header": "id", "accessor": "id"},
|
||||||
{
|
{
|
||||||
"Header": "process_model_identifier",
|
"Header": "process_model_identifier",
|
||||||
"accessor": "process_model_identifier",
|
"accessor": "process_model_identifier",
|
||||||
},
|
},
|
||||||
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
|
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
|
||||||
{"Header": "id", "accessor": "id"},
|
|
||||||
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
|
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
|
||||||
{"Header": "status", "accessor": "status"},
|
{"Header": "status", "accessor": "status"},
|
||||||
],
|
],
|
||||||
|
"filter_by": [{"field_name": "initiated_by_me", "field_value": True}],
|
||||||
},
|
},
|
||||||
"system_report_instances_with_tasks_completed_by_me": {
|
"system_report_instances_with_tasks_completed_by_me": {
|
||||||
"columns": [
|
"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": "id", "accessor": "id"},
|
||||||
{
|
{
|
||||||
"Header": "process_model_identifier",
|
"Header": "process_model_identifier",
|
||||||
"accessor": "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": {
|
"system_report_instances_with_tasks_completed_by_my_groups": {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
{"Header": "id", "accessor": "id"},
|
||||||
{
|
{
|
||||||
"Header": "process_model_identifier",
|
"Header": "process_model_identifier",
|
||||||
"accessor": "process_model_identifier",
|
"accessor": "process_model_identifier",
|
||||||
|
@ -104,7 +122,12 @@ class ProcessInstanceReportService:
|
||||||
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
|
{"Header": "start_in_seconds", "accessor": "start_in_seconds"},
|
||||||
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
|
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
|
||||||
{"Header": "status", "accessor": "status"},
|
{"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(
|
process_instance_report = ProcessInstanceReportModel(
|
||||||
identifier=report_identifier,
|
identifier=report_identifier,
|
||||||
created_by_id=user.id,
|
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
|
return process_instance_report # type: ignore
|
||||||
|
@ -138,6 +161,10 @@ class ProcessInstanceReportService:
|
||||||
"""Filter_from_metadata."""
|
"""Filter_from_metadata."""
|
||||||
filters = cls.filter_by_to_dict(process_instance_report)
|
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]:
|
def int_value(key: str) -> Optional[int]:
|
||||||
"""Int_value."""
|
"""Int_value."""
|
||||||
return int(filters[key]) if key in filters else None
|
return int(filters[key]) if key in filters else None
|
||||||
|
@ -152,6 +179,11 @@ class ProcessInstanceReportService:
|
||||||
end_from = int_value("end_from")
|
end_from = int_value("end_from")
|
||||||
end_to = int_value("end_to")
|
end_to = int_value("end_to")
|
||||||
process_status = list_value("process_status")
|
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(
|
report_filter = ProcessInstanceReportFilter(
|
||||||
process_model_identifier,
|
process_model_identifier,
|
||||||
|
@ -160,6 +192,9 @@ class ProcessInstanceReportService:
|
||||||
end_from,
|
end_from,
|
||||||
end_to,
|
end_to,
|
||||||
process_status,
|
process_status,
|
||||||
|
initiated_by_me,
|
||||||
|
with_tasks_completed_by_me,
|
||||||
|
with_tasks_completed_by_my_group,
|
||||||
)
|
)
|
||||||
|
|
||||||
return report_filter
|
return report_filter
|
||||||
|
@ -174,6 +209,9 @@ class ProcessInstanceReportService:
|
||||||
end_from: Optional[int] = None,
|
end_from: Optional[int] = None,
|
||||||
end_to: Optional[int] = None,
|
end_to: Optional[int] = None,
|
||||||
process_status: Optional[str] = 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:
|
) -> ProcessInstanceReportFilter:
|
||||||
"""Filter_from_metadata_with_overrides."""
|
"""Filter_from_metadata_with_overrides."""
|
||||||
report_filter = cls.filter_from_metadata(process_instance_report)
|
report_filter = cls.filter_from_metadata(process_instance_report)
|
||||||
|
@ -190,5 +228,13 @@ class ProcessInstanceReportService:
|
||||||
report_filter.end_to = end_to
|
report_filter.end_to = end_to
|
||||||
if process_status is not None:
|
if process_status is not None:
|
||||||
report_filter.process_status = process_status.split(",")
|
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
|
return report_filter
|
||||||
|
|
|
@ -8,6 +8,8 @@ export default function MyCompletedInstances() {
|
||||||
filtersEnabled={false}
|
filtersEnabled={false}
|
||||||
paginationQueryParamPrefix={paginationQueryParamPrefix}
|
paginationQueryParamPrefix={paginationQueryParamPrefix}
|
||||||
perPageOptions={[2, 5, 25]}
|
perPageOptions={[2, 5, 25]}
|
||||||
|
reportIdentifier="system_report_instances_initiated_by_me"
|
||||||
|
showReports={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ type OwnProps = {
|
||||||
paginationQueryParamPrefix?: string;
|
paginationQueryParamPrefix?: string;
|
||||||
perPageOptions?: number[];
|
perPageOptions?: number[];
|
||||||
showReports?: boolean;
|
showReports?: boolean;
|
||||||
|
reportIdentifier?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface dateParameters {
|
interface dateParameters {
|
||||||
|
@ -69,6 +70,7 @@ export default function ProcessInstanceListTable({
|
||||||
paginationQueryParamPrefix,
|
paginationQueryParamPrefix,
|
||||||
perPageOptions,
|
perPageOptions,
|
||||||
showReports = true,
|
showReports = true,
|
||||||
|
reportIdentifier,
|
||||||
}: OwnProps) {
|
}: OwnProps) {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
@ -173,9 +175,14 @@ export default function ProcessInstanceListTable({
|
||||||
queryParamString += `&user_filter=${userAppliedFilter}`;
|
queryParamString += `&user_filter=${userAppliedFilter}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reportIdentifier = searchParams.get('report_identifier');
|
let reportIdentifierToUse: any = reportIdentifier;
|
||||||
if (reportIdentifier) {
|
|
||||||
queryParamString += `&report_identifier=${reportIdentifier}`;
|
if (!reportIdentifierToUse) {
|
||||||
|
reportIdentifierToUse = searchParams.get('report_identifier');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reportIdentifierToUse) {
|
||||||
|
queryParamString += `&report_identifier=${reportIdentifierToUse}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(dateParametersToAlwaysFilterBy).forEach(
|
Object.keys(dateParametersToAlwaysFilterBy).forEach(
|
||||||
|
@ -273,6 +280,7 @@ export default function ProcessInstanceListTable({
|
||||||
paginationQueryParamPrefix,
|
paginationQueryParamPrefix,
|
||||||
processModelFullIdentifier,
|
processModelFullIdentifier,
|
||||||
perPageOptions,
|
perPageOptions,
|
||||||
|
reportIdentifier,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// This sets the filter data using the saved reports returned from the initial instance_list query.
|
// This sets the filter data using the saved reports returned from the initial instance_list query.
|
||||||
|
|
|
@ -1,5 +1,32 @@
|
||||||
import MyCompletedInstances from '../components/MyCompletedInstances';
|
import ProcessInstanceListTable from '../components/ProcessInstanceListTable';
|
||||||
|
|
||||||
export default function CompletedInstances() {
|
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}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue