Merge pull request #217 from sartography/feature/log_filters
Feature/log filters
This commit is contained in:
commit
991f177dad
|
@ -1959,10 +1959,34 @@ paths:
|
||||||
description: Show the detailed view, which includes all log entries
|
description: Show the detailed view, which includes all log entries
|
||||||
schema:
|
schema:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
- name: bpmn_name
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: The bpmn name of the task to search for.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: bpmn_identifier
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: The bpmn identifier of the task to search for.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: task_type
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: The task type of the task to search for.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: event_type
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: The type of the event to search for.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Process Instances
|
- Process Instance Events
|
||||||
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_log_list
|
operationId: spiffworkflow_backend.routes.process_instance_events_controller.log_list
|
||||||
summary: returns a list of logs associated with the process instance
|
summary: returns a list of logs associated with the process instance
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
|
@ -1972,6 +1996,20 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/ProcessInstanceLog"
|
$ref: "#/components/schemas/ProcessInstanceLog"
|
||||||
|
|
||||||
|
/logs/types:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Process Instance Events
|
||||||
|
operationId: spiffworkflow_backend.routes.process_instance_events_controller.types
|
||||||
|
summary: returns a list of task types and event typs. useful for building log queries.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: list of types
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ProcessInstanceLog"
|
||||||
|
|
||||||
/secrets:
|
/secrets:
|
||||||
parameters:
|
parameters:
|
||||||
- name: page
|
- name: page
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
"""Spiff_enum."""
|
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
|
|
||||||
class SpiffEnum(enum.Enum):
|
class SpiffEnum(enum.Enum):
|
||||||
"""SpiffEnum."""
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def list(cls) -> list[str]:
|
def list(cls) -> list[str]:
|
||||||
"""List."""
|
|
||||||
return [el.value for el in cls]
|
return [el.value for el in cls]
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import flask.wrappers
|
||||||
|
from flask import jsonify
|
||||||
|
from flask import make_response
|
||||||
|
from sqlalchemy import and_
|
||||||
|
|
||||||
|
from spiffworkflow_backend.models.bpmn_process_definition import BpmnProcessDefinitionModel
|
||||||
|
from spiffworkflow_backend.models.db import db
|
||||||
|
from spiffworkflow_backend.models.process_instance_event import ProcessInstanceEventModel
|
||||||
|
from spiffworkflow_backend.models.process_instance_event import ProcessInstanceEventType
|
||||||
|
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||||
|
from spiffworkflow_backend.models.task_definition import TaskDefinitionModel
|
||||||
|
from spiffworkflow_backend.models.user import UserModel
|
||||||
|
from spiffworkflow_backend.routes.process_api_blueprint import (
|
||||||
|
_find_process_instance_by_id_or_raise,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def log_list(
|
||||||
|
modified_process_model_identifier: str,
|
||||||
|
process_instance_id: int,
|
||||||
|
page: int = 1,
|
||||||
|
per_page: int = 100,
|
||||||
|
detailed: bool = False,
|
||||||
|
bpmn_name: Optional[str] = None,
|
||||||
|
bpmn_identifier: Optional[str] = None,
|
||||||
|
task_type: Optional[str] = None,
|
||||||
|
event_type: Optional[str] = None,
|
||||||
|
) -> flask.wrappers.Response:
|
||||||
|
# to make sure the process instance exists
|
||||||
|
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||||
|
|
||||||
|
log_query = (
|
||||||
|
ProcessInstanceEventModel.query.filter_by(process_instance_id=process_instance.id)
|
||||||
|
.outerjoin(TaskModel, TaskModel.guid == ProcessInstanceEventModel.task_guid)
|
||||||
|
.outerjoin(TaskDefinitionModel, TaskDefinitionModel.id == TaskModel.task_definition_id)
|
||||||
|
.outerjoin(
|
||||||
|
BpmnProcessDefinitionModel,
|
||||||
|
BpmnProcessDefinitionModel.id == TaskDefinitionModel.bpmn_process_definition_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if not detailed:
|
||||||
|
log_query = log_query.filter(
|
||||||
|
and_(
|
||||||
|
TaskModel.state.in_(["COMPLETED"]), # type: ignore
|
||||||
|
TaskDefinitionModel.typename.in_(["IntermediateThrowEvent"]), # type: ignore
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if bpmn_name is not None:
|
||||||
|
log_query = log_query.filter(TaskDefinitionModel.bpmn_name == bpmn_name)
|
||||||
|
if bpmn_identifier is not None:
|
||||||
|
log_query = log_query.filter(TaskDefinitionModel.bpmn_identifier == bpmn_identifier)
|
||||||
|
if task_type is not None:
|
||||||
|
log_query = log_query.filter(TaskDefinitionModel.typename == task_type)
|
||||||
|
if event_type is not None:
|
||||||
|
log_query = log_query.filter(ProcessInstanceEventModel.event_type == event_type)
|
||||||
|
|
||||||
|
logs = (
|
||||||
|
log_query.order_by(
|
||||||
|
ProcessInstanceEventModel.timestamp.desc(), ProcessInstanceEventModel.id.desc() # type: ignore
|
||||||
|
)
|
||||||
|
.outerjoin(UserModel, UserModel.id == ProcessInstanceEventModel.user_id)
|
||||||
|
.add_columns(
|
||||||
|
TaskModel.guid.label("spiff_task_guid"), # type: ignore
|
||||||
|
UserModel.username,
|
||||||
|
BpmnProcessDefinitionModel.bpmn_identifier.label("bpmn_process_definition_identifier"), # type: ignore
|
||||||
|
BpmnProcessDefinitionModel.bpmn_name.label("bpmn_process_definition_name"), # type: ignore
|
||||||
|
TaskDefinitionModel.bpmn_identifier.label("task_definition_identifier"), # type: ignore
|
||||||
|
TaskDefinitionModel.bpmn_name.label("task_definition_name"), # type: ignore
|
||||||
|
TaskDefinitionModel.typename.label("bpmn_task_type"), # type: ignore
|
||||||
|
)
|
||||||
|
.paginate(page=page, per_page=per_page, error_out=False)
|
||||||
|
)
|
||||||
|
|
||||||
|
response_json = {
|
||||||
|
"results": logs.items,
|
||||||
|
"pagination": {
|
||||||
|
"count": len(logs.items),
|
||||||
|
"total": logs.total,
|
||||||
|
"pages": logs.pages,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return make_response(jsonify(response_json), 200)
|
||||||
|
|
||||||
|
|
||||||
|
def types() -> flask.wrappers.Response:
|
||||||
|
query = db.session.query(TaskDefinitionModel.typename).distinct() # type: ignore
|
||||||
|
task_types = [t.typename for t in query]
|
||||||
|
event_types = ProcessInstanceEventType.list()
|
||||||
|
return make_response(jsonify({"task_types": task_types, "event_types": event_types}), 200)
|
|
@ -30,9 +30,6 @@ from spiffworkflow_backend.models.process_instance import (
|
||||||
)
|
)
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema
|
from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema
|
||||||
from spiffworkflow_backend.models.process_instance_event import (
|
|
||||||
ProcessInstanceEventModel,
|
|
||||||
)
|
|
||||||
from spiffworkflow_backend.models.process_instance_metadata import (
|
from spiffworkflow_backend.models.process_instance_metadata import (
|
||||||
ProcessInstanceMetadataModel,
|
ProcessInstanceMetadataModel,
|
||||||
)
|
)
|
||||||
|
@ -47,7 +44,6 @@ from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
|
||||||
from spiffworkflow_backend.models.spec_reference import SpecReferenceNotFoundError
|
from spiffworkflow_backend.models.spec_reference import SpecReferenceNotFoundError
|
||||||
from spiffworkflow_backend.models.task import TaskModel
|
from spiffworkflow_backend.models.task import TaskModel
|
||||||
from spiffworkflow_backend.models.task_definition import TaskDefinitionModel
|
from spiffworkflow_backend.models.task_definition import TaskDefinitionModel
|
||||||
from spiffworkflow_backend.models.user import UserModel
|
|
||||||
from spiffworkflow_backend.routes.process_api_blueprint import (
|
from spiffworkflow_backend.routes.process_api_blueprint import (
|
||||||
_find_process_instance_by_id_or_raise,
|
_find_process_instance_by_id_or_raise,
|
||||||
)
|
)
|
||||||
|
@ -224,63 +220,6 @@ def process_instance_resume(
|
||||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||||
|
|
||||||
|
|
||||||
def process_instance_log_list(
|
|
||||||
modified_process_model_identifier: str,
|
|
||||||
process_instance_id: int,
|
|
||||||
page: int = 1,
|
|
||||||
per_page: int = 100,
|
|
||||||
detailed: bool = False,
|
|
||||||
) -> flask.wrappers.Response:
|
|
||||||
"""Process_instance_log_list."""
|
|
||||||
# to make sure the process instance exists
|
|
||||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
|
||||||
|
|
||||||
log_query = (
|
|
||||||
ProcessInstanceEventModel.query.filter_by(process_instance_id=process_instance.id)
|
|
||||||
.outerjoin(TaskModel, TaskModel.guid == ProcessInstanceEventModel.task_guid)
|
|
||||||
.outerjoin(TaskDefinitionModel, TaskDefinitionModel.id == TaskModel.task_definition_id)
|
|
||||||
.outerjoin(
|
|
||||||
BpmnProcessDefinitionModel,
|
|
||||||
BpmnProcessDefinitionModel.id == TaskDefinitionModel.bpmn_process_definition_id,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if not detailed:
|
|
||||||
log_query = log_query.filter(
|
|
||||||
and_(
|
|
||||||
TaskModel.state.in_(["COMPLETED"]), # type: ignore
|
|
||||||
TaskDefinitionModel.typename.in_(["IntermediateThrowEvent"]), # type: ignore
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
logs = (
|
|
||||||
log_query.order_by(
|
|
||||||
ProcessInstanceEventModel.timestamp.desc(), ProcessInstanceEventModel.id.desc() # type: ignore
|
|
||||||
)
|
|
||||||
.outerjoin(UserModel, UserModel.id == ProcessInstanceEventModel.user_id)
|
|
||||||
.add_columns(
|
|
||||||
TaskModel.guid.label("spiff_task_guid"), # type: ignore
|
|
||||||
UserModel.username,
|
|
||||||
BpmnProcessDefinitionModel.bpmn_identifier.label("bpmn_process_definition_identifier"), # type: ignore
|
|
||||||
BpmnProcessDefinitionModel.bpmn_name.label("bpmn_process_definition_name"), # type: ignore
|
|
||||||
TaskDefinitionModel.bpmn_identifier.label("task_definition_identifier"), # type: ignore
|
|
||||||
TaskDefinitionModel.bpmn_name.label("task_definition_name"), # type: ignore
|
|
||||||
TaskDefinitionModel.typename.label("bpmn_task_type"), # type: ignore
|
|
||||||
)
|
|
||||||
.paginate(page=page, per_page=per_page, error_out=False)
|
|
||||||
)
|
|
||||||
|
|
||||||
response_json = {
|
|
||||||
"results": logs.items,
|
|
||||||
"pagination": {
|
|
||||||
"count": len(logs.items),
|
|
||||||
"total": logs.total,
|
|
||||||
"pages": logs.pages,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return make_response(jsonify(response_json), 200)
|
|
||||||
|
|
||||||
|
|
||||||
def process_instance_list_for_me(
|
def process_instance_list_for_me(
|
||||||
process_model_identifier: Optional[str] = None,
|
process_model_identifier: Optional[str] = None,
|
||||||
page: int = 1,
|
page: int = 1,
|
||||||
|
|
|
@ -567,6 +567,7 @@ class AuthorizationService:
|
||||||
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/processes"))
|
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/processes"))
|
||||||
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/service-tasks"))
|
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/service-tasks"))
|
||||||
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/user-groups/for-current-user"))
|
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/user-groups/for-current-user"))
|
||||||
|
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/logs/types"))
|
||||||
permissions_to_assign.append(PermissionToAssign(permission="create", target_uri="/users/exists/by-username"))
|
permissions_to_assign.append(PermissionToAssign(permission="create", target_uri="/users/exists/by-username"))
|
||||||
permissions_to_assign.append(
|
permissions_to_assign.append(
|
||||||
PermissionToAssign(permission="read", target_uri="/process-instances/find-by-id/*")
|
PermissionToAssign(permission="read", target_uri="/process-instances/find-by-id/*")
|
||||||
|
|
|
@ -275,6 +275,7 @@ class TestAuthorizationService(BaseTest):
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test_explode_permissions_basic."""
|
"""Test_explode_permissions_basic."""
|
||||||
expected_permissions = [
|
expected_permissions = [
|
||||||
|
("/logs/types", "read"),
|
||||||
("/process-instances/find-by-id/*", "read"),
|
("/process-instances/find-by-id/*", "read"),
|
||||||
("/process-instances/for-me", "read"),
|
("/process-instances/for-me", "read"),
|
||||||
("/process-instances/reports/*", "create"),
|
("/process-instances/reports/*", "create"),
|
||||||
|
|
|
@ -58,11 +58,12 @@
|
||||||
"react-icons": "^4.4.0",
|
"react-icons": "^4.4.0",
|
||||||
"react-jsonschema-form": "^1.8.1",
|
"react-jsonschema-form": "^1.8.1",
|
||||||
"react-router": "^6.3.0",
|
"react-router": "^6.3.0",
|
||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "6.3.0",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"serve": "^14.0.0",
|
"serve": "^14.0.0",
|
||||||
"timepicker": "^1.13.18",
|
"timepicker": "^1.13.18",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
|
"use-debounce": "^9.0.4",
|
||||||
"web-vitals": "^3.0.2"
|
"web-vitals": "^3.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -15500,6 +15501,14 @@
|
||||||
"he": "bin/he"
|
"he": "bin/he"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/history": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.7.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hmac-drbg": {
|
"node_modules/hmac-drbg": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||||
|
@ -25507,21 +25516,29 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router-dom": {
|
"node_modules/react-router-dom": {
|
||||||
"version": "6.10.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
|
||||||
"integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==",
|
"integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remix-run/router": "1.5.0",
|
"history": "^5.2.0",
|
||||||
"react-router": "6.10.0"
|
"react-router": "6.3.0"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=16.8",
|
"react": ">=16.8",
|
||||||
"react-dom": ">=16.8"
|
"react-dom": ">=16.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-router-dom/node_modules/react-router": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"history": "^5.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-scripts": {
|
"node_modules/react-scripts": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||||
|
@ -30671,6 +30688,17 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-debounce": {
|
||||||
|
"version": "9.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-9.0.4.tgz",
|
||||||
|
"integrity": "sha512-6X8H/mikbrt0XE8e+JXRtZ8yYVvKkdYRfmIhWZYsP8rcNs9hk3APV8Ua2mFkKRLcJKVdnX2/Vwrmg2GWKUQEaQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/use-resize-observer": {
|
"node_modules/use-resize-observer": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-6.1.0.tgz",
|
||||||
|
@ -43754,6 +43782,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||||
},
|
},
|
||||||
|
"history": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.7.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"hmac-drbg": {
|
"hmac-drbg": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||||
|
@ -50970,12 +51006,22 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-router-dom": {
|
"react-router-dom": {
|
||||||
"version": "6.10.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz",
|
||||||
"integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==",
|
"integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@remix-run/router": "1.5.0",
|
"history": "^5.2.0",
|
||||||
"react-router": "6.10.0"
|
"react-router": "6.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react-router": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==",
|
||||||
|
"requires": {
|
||||||
|
"history": "^5.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-scripts": {
|
"react-scripts": {
|
||||||
|
@ -54978,6 +55024,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||||
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
|
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
|
||||||
},
|
},
|
||||||
|
"use-debounce": {
|
||||||
|
"version": "9.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-9.0.4.tgz",
|
||||||
|
"integrity": "sha512-6X8H/mikbrt0XE8e+JXRtZ8yYVvKkdYRfmIhWZYsP8rcNs9hk3APV8Ua2mFkKRLcJKVdnX2/Vwrmg2GWKUQEaQ==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"use-resize-observer": {
|
"use-resize-observer": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-6.1.0.tgz",
|
||||||
|
|
|
@ -53,11 +53,12 @@
|
||||||
"react-icons": "^4.4.0",
|
"react-icons": "^4.4.0",
|
||||||
"react-jsonschema-form": "^1.8.1",
|
"react-jsonschema-form": "^1.8.1",
|
||||||
"react-router": "^6.3.0",
|
"react-router": "^6.3.0",
|
||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "6.3.0",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"serve": "^14.0.0",
|
"serve": "^14.0.0",
|
||||||
"timepicker": "^1.13.18",
|
"timepicker": "^1.13.18",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
|
"use-debounce": "^9.0.4",
|
||||||
"web-vitals": "^3.0.2"
|
"web-vitals": "^3.0.2"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
// @ts-ignore
|
||||||
|
import { Filter } from '@carbon/icons-react';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Grid,
|
||||||
|
Column,
|
||||||
|
// @ts-ignore
|
||||||
|
} from '@carbon/react';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
showFilterOptions: boolean;
|
||||||
|
setShowFilterOptions: Function;
|
||||||
|
filterOptions: Function;
|
||||||
|
filtersEnabled?: boolean;
|
||||||
|
reportSearchComponent?: Function | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Filters({
|
||||||
|
showFilterOptions,
|
||||||
|
setShowFilterOptions,
|
||||||
|
filterOptions,
|
||||||
|
reportSearchComponent = null,
|
||||||
|
filtersEnabled = true,
|
||||||
|
}: OwnProps) {
|
||||||
|
const toggleShowFilterOptions = () => {
|
||||||
|
setShowFilterOptions(!showFilterOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (filtersEnabled) {
|
||||||
|
let reportSearchSection = null;
|
||||||
|
if (reportSearchComponent) {
|
||||||
|
reportSearchSection = (
|
||||||
|
<Column sm={2} md={4} lg={7}>
|
||||||
|
{reportSearchComponent()}
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Grid fullWidth>
|
||||||
|
{reportSearchSection}
|
||||||
|
<Column
|
||||||
|
className="filterIcon"
|
||||||
|
sm={{ span: 1, offset: 3 }}
|
||||||
|
md={{ span: 1, offset: 7 }}
|
||||||
|
lg={{ span: 1, offset: 15 }}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
data-qa="filter-section-expand-toggle"
|
||||||
|
renderIcon={Filter}
|
||||||
|
iconDescription="Filter Options"
|
||||||
|
hasIconOnly
|
||||||
|
size="lg"
|
||||||
|
onClick={toggleShowFilterOptions}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
</Grid>
|
||||||
|
{filterOptions()}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { Filter, Close, AddAlt } from '@carbon/icons-react';
|
import { Close, AddAlt } from '@carbon/icons-react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ButtonSet,
|
ButtonSet,
|
||||||
|
@ -71,6 +71,7 @@ import { usePermissionFetcher } from '../hooks/PermissionService';
|
||||||
import { Can } from '../contexts/Can';
|
import { Can } from '../contexts/Can';
|
||||||
import TableCellWithTimeAgoInWords from './TableCellWithTimeAgoInWords';
|
import TableCellWithTimeAgoInWords from './TableCellWithTimeAgoInWords';
|
||||||
import UserService from '../services/UserService';
|
import UserService from '../services/UserService';
|
||||||
|
import Filters from './Filters';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
filtersEnabled?: boolean;
|
filtersEnabled?: boolean;
|
||||||
|
@ -1506,10 +1507,6 @@ export default function ProcessInstanceListTable({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleShowFilterOptions = () => {
|
|
||||||
setShowFilterOptions(!showFilterOptions);
|
|
||||||
};
|
|
||||||
|
|
||||||
const reportSearchComponent = () => {
|
const reportSearchComponent = () => {
|
||||||
if (showReports) {
|
if (showReports) {
|
||||||
const columns = [
|
const columns = [
|
||||||
|
@ -1529,37 +1526,6 @@ export default function ProcessInstanceListTable({
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const filterComponent = () => {
|
|
||||||
if (!filtersEnabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Grid fullWidth>
|
|
||||||
<Column sm={2} md={4} lg={7}>
|
|
||||||
{reportSearchComponent()}
|
|
||||||
</Column>
|
|
||||||
<Column
|
|
||||||
className="filterIcon"
|
|
||||||
sm={{ span: 1, offset: 3 }}
|
|
||||||
md={{ span: 1, offset: 7 }}
|
|
||||||
lg={{ span: 1, offset: 15 }}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
data-qa="filter-section-expand-toggle"
|
|
||||||
renderIcon={Filter}
|
|
||||||
iconDescription="Filter Options"
|
|
||||||
hasIconOnly
|
|
||||||
size="lg"
|
|
||||||
onClick={toggleShowFilterOptions}
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
</Grid>
|
|
||||||
{filterOptions()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (pagination && (!textToShowIfEmpty || pagination.total > 0)) {
|
if (pagination && (!textToShowIfEmpty || pagination.total > 0)) {
|
||||||
// eslint-disable-next-line prefer-const
|
// eslint-disable-next-line prefer-const
|
||||||
let { page, perPage } = getPageInfoFromSearchParams(
|
let { page, perPage } = getPageInfoFromSearchParams(
|
||||||
|
@ -1599,7 +1565,13 @@ export default function ProcessInstanceListTable({
|
||||||
<>
|
<>
|
||||||
{reportColumnForm()}
|
{reportColumnForm()}
|
||||||
{processInstanceReportSaveTag()}
|
{processInstanceReportSaveTag()}
|
||||||
{filterComponent()}
|
<Filters
|
||||||
|
filterOptions={filterOptions}
|
||||||
|
showFilterOptions={showFilterOptions}
|
||||||
|
setShowFilterOptions={setShowFilterOptions}
|
||||||
|
reportSearchComponent={reportSearchComponent}
|
||||||
|
filtersEnabled={filtersEnabled}
|
||||||
|
/>
|
||||||
{resultsTable}
|
{resultsTable}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -26,6 +26,17 @@ export const underscorizeString = (inputString: string) => {
|
||||||
return slugifyString(inputString).replace(/-/g, '_');
|
return slugifyString(inputString).replace(/-/g, '_');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const selectKeysFromSearchParams = (obj: any, keys: string[]) => {
|
||||||
|
const newSearchParams: { [key: string]: string } = {};
|
||||||
|
keys.forEach((key: string) => {
|
||||||
|
const value = obj.get(key);
|
||||||
|
if (value) {
|
||||||
|
newSearchParams[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return newSearchParams;
|
||||||
|
};
|
||||||
|
|
||||||
export const capitalizeFirstLetter = (string: any) => {
|
export const capitalizeFirstLetter = (string: any) => {
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,35 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
// @ts-ignore
|
import {
|
||||||
import { Table, Tabs, TabList, Tab } from '@carbon/react';
|
Table,
|
||||||
import { Link, useParams, useSearchParams } from 'react-router-dom';
|
Tabs,
|
||||||
|
TabList,
|
||||||
|
Tab,
|
||||||
|
Grid,
|
||||||
|
Column,
|
||||||
|
ButtonSet,
|
||||||
|
Button,
|
||||||
|
TextInput,
|
||||||
|
ComboBox,
|
||||||
|
// @ts-ignore
|
||||||
|
} from '@carbon/react';
|
||||||
|
import {
|
||||||
|
createSearchParams,
|
||||||
|
Link,
|
||||||
|
useParams,
|
||||||
|
useSearchParams,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
import PaginationForTable from '../components/PaginationForTable';
|
import PaginationForTable from '../components/PaginationForTable';
|
||||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||||
import {
|
import {
|
||||||
getPageInfoFromSearchParams,
|
getPageInfoFromSearchParams,
|
||||||
convertSecondsToFormattedDateTime,
|
convertSecondsToFormattedDateTime,
|
||||||
|
selectKeysFromSearchParams,
|
||||||
} from '../helpers';
|
} from '../helpers';
|
||||||
import HttpService from '../services/HttpService';
|
import HttpService from '../services/HttpService';
|
||||||
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
||||||
import { ProcessInstanceLogEntry } from '../interfaces';
|
import { ProcessInstanceLogEntry } from '../interfaces';
|
||||||
|
import Filters from '../components/Filters';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
variant: string;
|
variant: string;
|
||||||
|
@ -21,14 +40,42 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const [processInstanceLogs, setProcessInstanceLogs] = useState([]);
|
const [processInstanceLogs, setProcessInstanceLogs] = useState([]);
|
||||||
const [pagination, setPagination] = useState(null);
|
const [pagination, setPagination] = useState(null);
|
||||||
|
|
||||||
|
const [taskName, setTaskName] = useState<string>('');
|
||||||
|
const [taskIdentifier, setTaskIdentifier] = useState<string>('');
|
||||||
|
|
||||||
|
const [taskTypes, setTaskTypes] = useState<string[]>([]);
|
||||||
|
const [eventTypes, setEventTypes] = useState<string[]>([]);
|
||||||
|
|
||||||
const { targetUris } = useUriListForPermissions();
|
const { targetUris } = useUriListForPermissions();
|
||||||
const isDetailedView = searchParams.get('detailed') === 'true';
|
const isDetailedView = searchParams.get('detailed') === 'true';
|
||||||
|
|
||||||
|
const taskNameHeader = isDetailedView ? 'Task Name' : 'Milestone';
|
||||||
|
|
||||||
|
const [showFilterOptions, setShowFilterOptions] = useState<boolean>(false);
|
||||||
|
|
||||||
let processInstanceShowPageBaseUrl = `/admin/process-instances/for-me/${params.process_model_id}`;
|
let processInstanceShowPageBaseUrl = `/admin/process-instances/for-me/${params.process_model_id}`;
|
||||||
if (variant === 'all') {
|
if (variant === 'all') {
|
||||||
processInstanceShowPageBaseUrl = `/admin/process-instances/${params.process_model_id}`;
|
processInstanceShowPageBaseUrl = `/admin/process-instances/${params.process_model_id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateSearchParams = (value: string, key: string) => {
|
||||||
|
if (value) {
|
||||||
|
searchParams.set(key, value);
|
||||||
|
} else {
|
||||||
|
searchParams.delete(key);
|
||||||
|
}
|
||||||
|
setSearchParams(searchParams);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addDebouncedSearchParams = useDebouncedCallback(
|
||||||
|
(value: string, key: string) => {
|
||||||
|
updateSearchParams(value, key);
|
||||||
|
},
|
||||||
|
// delay in ms
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Clear out any previous results to avoid a "flicker" effect where columns
|
// Clear out any previous results to avoid a "flicker" effect where columns
|
||||||
// are updated above the incorrect data.
|
// are updated above the incorrect data.
|
||||||
|
@ -39,11 +86,41 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
setProcessInstanceLogs(result.results);
|
setProcessInstanceLogs(result.results);
|
||||||
setPagination(result.pagination);
|
setPagination(result.pagination);
|
||||||
};
|
};
|
||||||
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
|
|
||||||
|
const searchParamsToInclude = [
|
||||||
|
'detailed',
|
||||||
|
'page',
|
||||||
|
'per_page',
|
||||||
|
'bpmn_name',
|
||||||
|
'bpmn_identifier',
|
||||||
|
'task_type',
|
||||||
|
'event_type',
|
||||||
|
];
|
||||||
|
const pickedSearchParams = selectKeysFromSearchParams(
|
||||||
|
searchParams,
|
||||||
|
searchParamsToInclude
|
||||||
|
);
|
||||||
|
|
||||||
|
if ('bpmn_name' in pickedSearchParams) {
|
||||||
|
setTaskName(pickedSearchParams.bpmn_name);
|
||||||
|
}
|
||||||
|
if ('bpmn_identifier' in pickedSearchParams) {
|
||||||
|
setTaskIdentifier(pickedSearchParams.bpmn_identifier);
|
||||||
|
}
|
||||||
|
|
||||||
HttpService.makeCallToBackend({
|
HttpService.makeCallToBackend({
|
||||||
path: `${targetUris.processInstanceLogListPath}?per_page=${perPage}&page=${page}&detailed=${isDetailedView}`,
|
path: `${targetUris.processInstanceLogListPath}?${createSearchParams(
|
||||||
|
pickedSearchParams
|
||||||
|
)}`,
|
||||||
successCallback: setProcessInstanceLogListFromResult,
|
successCallback: setProcessInstanceLogListFromResult,
|
||||||
});
|
});
|
||||||
|
HttpService.makeCallToBackend({
|
||||||
|
path: `/v1.0/logs/types`,
|
||||||
|
successCallback: (result: any) => {
|
||||||
|
setTaskTypes(result.task_types);
|
||||||
|
setEventTypes(result.event_types);
|
||||||
|
},
|
||||||
|
});
|
||||||
}, [
|
}, [
|
||||||
searchParams,
|
searchParams,
|
||||||
params,
|
params,
|
||||||
|
@ -85,6 +162,7 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
if (isDetailedView) {
|
if (isDetailedView) {
|
||||||
tableRow.push(
|
tableRow.push(
|
||||||
<>
|
<>
|
||||||
|
<td>{logEntry.task_definition_identifier}</td>
|
||||||
<td>{logEntry.bpmn_task_type}</td>
|
<td>{logEntry.bpmn_task_type}</td>
|
||||||
<td>{logEntry.event_type}</td>
|
<td>{logEntry.event_type}</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -130,13 +208,13 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
<>
|
<>
|
||||||
<th>Id</th>
|
<th>Id</th>
|
||||||
<th>Bpmn Process</th>
|
<th>Bpmn Process</th>
|
||||||
<th>Task Name</th>
|
<th>{taskNameHeader}</th>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
tableHeaders.push(
|
tableHeaders.push(
|
||||||
<>
|
<>
|
||||||
<th>Event</th>
|
<th>{taskNameHeader}</th>
|
||||||
<th>Bpmn Process</th>
|
<th>Bpmn Process</th>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -144,8 +222,9 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
if (isDetailedView) {
|
if (isDetailedView) {
|
||||||
tableHeaders.push(
|
tableHeaders.push(
|
||||||
<>
|
<>
|
||||||
|
<th>Task Identifier</th>
|
||||||
<th>Task Type</th>
|
<th>Task Type</th>
|
||||||
<th>Event</th>
|
<th>Event Type</th>
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -160,27 +239,126 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
</Table>
|
</Table>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const selectedTabIndex = isDetailedView ? 1 : 0;
|
|
||||||
|
|
||||||
if (pagination) {
|
const resetFilters = () => {
|
||||||
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
|
setTaskIdentifier('');
|
||||||
|
setTaskName('');
|
||||||
|
|
||||||
|
['bpmn_name', 'bpmn_identifier', 'task_type', 'event_type'].forEach(
|
||||||
|
(value: string) => searchParams.delete(value)
|
||||||
|
);
|
||||||
|
|
||||||
|
setSearchParams(searchParams);
|
||||||
|
};
|
||||||
|
|
||||||
|
const shouldFilterStringItem = (options: any) => {
|
||||||
|
const stringItem = options.item;
|
||||||
|
let { inputValue } = options;
|
||||||
|
if (!inputValue) {
|
||||||
|
inputValue = '';
|
||||||
|
}
|
||||||
|
return stringItem.toLowerCase().includes(inputValue.toLowerCase());
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterOptions = () => {
|
||||||
|
if (!showFilterOptions) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterElements = [];
|
||||||
|
filterElements.push(
|
||||||
|
<Column md={4}>
|
||||||
|
<TextInput
|
||||||
|
id="task-name-filter"
|
||||||
|
labelText={taskNameHeader}
|
||||||
|
value={taskName}
|
||||||
|
onChange={(event: any) => {
|
||||||
|
const newValue = event.target.value;
|
||||||
|
setTaskName(newValue);
|
||||||
|
addDebouncedSearchParams(newValue, 'bpmn_name');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isDetailedView) {
|
||||||
|
filterElements.push(
|
||||||
|
<>
|
||||||
|
<Column md={4}>
|
||||||
|
<TextInput
|
||||||
|
id="task-identifier-filter"
|
||||||
|
labelText="Task Identifier"
|
||||||
|
value={taskIdentifier}
|
||||||
|
onChange={(event: any) => {
|
||||||
|
const newValue = event.target.value;
|
||||||
|
setTaskIdentifier(newValue);
|
||||||
|
addDebouncedSearchParams(newValue, 'bpmn_identifier');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
<Column md={4}>
|
||||||
|
<ComboBox
|
||||||
|
onChange={(value: any) => {
|
||||||
|
updateSearchParams(value.selectedItem, 'task_type');
|
||||||
|
}}
|
||||||
|
id="task-type-select"
|
||||||
|
data-qa="task-type-select"
|
||||||
|
items={taskTypes}
|
||||||
|
itemToString={(value: string) => {
|
||||||
|
return value;
|
||||||
|
}}
|
||||||
|
shouldFilterItem={shouldFilterStringItem}
|
||||||
|
placeholder="Choose a process model"
|
||||||
|
titleText="Task Type"
|
||||||
|
selectedItem={searchParams.get('task_type')}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
<Column md={4}>
|
||||||
|
<ComboBox
|
||||||
|
onChange={(value: any) => {
|
||||||
|
updateSearchParams(value.selectedItem, 'event_type');
|
||||||
|
}}
|
||||||
|
id="event-type-select"
|
||||||
|
data-qa="event-type-select"
|
||||||
|
items={eventTypes}
|
||||||
|
itemToString={(value: string) => {
|
||||||
|
return value;
|
||||||
|
}}
|
||||||
|
shouldFilterItem={shouldFilterStringItem}
|
||||||
|
placeholder="Choose a process model"
|
||||||
|
titleText="Event Type"
|
||||||
|
selectedItem={searchParams.get('event_type')}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ProcessBreadcrumb
|
<Grid fullWidth className="with-bottom-margin">
|
||||||
hotCrumbs={[
|
{filterElements}
|
||||||
['Process Groups', '/admin'],
|
</Grid>
|
||||||
{
|
<Grid fullWidth className="with-bottom-margin">
|
||||||
entityToExplode: params.process_model_id || '',
|
<Column sm={4} md={4} lg={8}>
|
||||||
entityType: 'process-model-id',
|
<ButtonSet>
|
||||||
linkLastItem: true,
|
<Button
|
||||||
},
|
kind=""
|
||||||
[
|
className="button-white-background narrow-button"
|
||||||
`Process Instance: ${params.process_instance_id}`,
|
onClick={resetFilters}
|
||||||
`${processInstanceShowPageBaseUrl}/${params.process_instance_id}`,
|
>
|
||||||
],
|
Reset
|
||||||
['Logs'],
|
</Button>
|
||||||
]}
|
</ButtonSet>
|
||||||
/>
|
</Column>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const tabs = () => {
|
||||||
|
const selectedTabIndex = isDetailedView ? 1 : 0;
|
||||||
|
return (
|
||||||
<Tabs selectedIndex={selectedTabIndex}>
|
<Tabs selectedIndex={selectedTabIndex}>
|
||||||
<TabList aria-label="List of tabs">
|
<TabList aria-label="List of tabs">
|
||||||
<Tab
|
<Tab
|
||||||
|
@ -205,6 +383,34 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
</Tab>
|
</Tab>
|
||||||
</TabList>
|
</TabList>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ProcessBreadcrumb
|
||||||
|
hotCrumbs={[
|
||||||
|
['Process Groups', '/admin'],
|
||||||
|
{
|
||||||
|
entityToExplode: params.process_model_id || '',
|
||||||
|
entityType: 'process-model-id',
|
||||||
|
linkLastItem: true,
|
||||||
|
},
|
||||||
|
[
|
||||||
|
`Process Instance: ${params.process_instance_id}`,
|
||||||
|
`${processInstanceShowPageBaseUrl}/${params.process_instance_id}`,
|
||||||
|
],
|
||||||
|
['Logs'],
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
{tabs()}
|
||||||
|
<Filters
|
||||||
|
filterOptions={filterOptions}
|
||||||
|
showFilterOptions={showFilterOptions}
|
||||||
|
setShowFilterOptions={setShowFilterOptions}
|
||||||
|
filtersEnabled
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
<PaginationForTable
|
<PaginationForTable
|
||||||
page={page}
|
page={page}
|
||||||
|
@ -214,6 +420,4 @@ export default function ProcessInstanceLogList({ variant }: OwnProps) {
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -890,7 +890,7 @@ export default function ProcessModelEditDiagram() {
|
||||||
const path = generatePath(
|
const path = generatePath(
|
||||||
'/admin/process-models/:process_model_id/form/:file_name',
|
'/admin/process-models/:process_model_id/form/:file_name',
|
||||||
{
|
{
|
||||||
process_model_id: params.process_model_id || null,
|
process_model_id: params.process_model_id,
|
||||||
file_name: fileName,
|
file_name: fileName,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -902,7 +902,7 @@ export default function ProcessModelEditDiagram() {
|
||||||
const path = generatePath(
|
const path = generatePath(
|
||||||
'/admin/process-models/:process_model_id/files/:file_name',
|
'/admin/process-models/:process_model_id/files/:file_name',
|
||||||
{
|
{
|
||||||
process_model_id: params.process_model_id || null,
|
process_model_id: params.process_model_id,
|
||||||
file_name: file.name,
|
file_name: file.name,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue