Merge pull request #95 from sartography/feature/find_by_process_instance_id
Feature/find by process instance
This commit is contained in:
commit
6dff495aa6
|
@ -946,6 +946,27 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/Workflow"
|
$ref: "#/components/schemas/Workflow"
|
||||||
|
|
||||||
|
/process-instances/find-by-id/{process_instance_id}:
|
||||||
|
parameters:
|
||||||
|
- name: process_instance_id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The unique id of an existing process instance.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
get:
|
||||||
|
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_find_by_id
|
||||||
|
summary: Find a process instance based on its id only
|
||||||
|
tags:
|
||||||
|
- Process Instances
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: One Process Instance
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Workflow"
|
||||||
|
|
||||||
/process-instances/{modified_process_model_identifier}/{process_instance_id}:
|
/process-instances/{modified_process_model_identifier}/{process_instance_id}:
|
||||||
parameters:
|
parameters:
|
||||||
- name: modified_process_model_identifier
|
- name: modified_process_model_identifier
|
||||||
|
|
|
@ -30,6 +30,12 @@ permissions:
|
||||||
allowed_permissions: [read]
|
allowed_permissions: [read]
|
||||||
uri: /*
|
uri: /*
|
||||||
|
|
||||||
|
process-instances-find-by-id:
|
||||||
|
groups: [everybody]
|
||||||
|
users: []
|
||||||
|
allowed_permissions: [read]
|
||||||
|
uri: /process-instances/find-by-id/*
|
||||||
|
|
||||||
tasks-crud:
|
tasks-crud:
|
||||||
groups: [everybody]
|
groups: [everybody]
|
||||||
users: []
|
users: []
|
||||||
|
|
|
@ -58,6 +58,14 @@ class ProcessModelInfo:
|
||||||
"""Id_for_file_path."""
|
"""Id_for_file_path."""
|
||||||
return self.id.replace("/", os.sep)
|
return self.id.replace("/", os.sep)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def modify_process_identifier_for_path_param(cls, identifier: str) -> str:
|
||||||
|
"""Identifier."""
|
||||||
|
if "\\" in identifier:
|
||||||
|
raise Exception(f"Found backslash in identifier: {identifier}")
|
||||||
|
|
||||||
|
return identifier.replace("/", ":")
|
||||||
|
|
||||||
|
|
||||||
class ProcessModelInfoSchema(Schema):
|
class ProcessModelInfoSchema(Schema):
|
||||||
"""ProcessModelInfoSchema."""
|
"""ProcessModelInfoSchema."""
|
||||||
|
|
|
@ -31,6 +31,7 @@ from spiffworkflow_backend.models.process_instance_metadata import (
|
||||||
from spiffworkflow_backend.models.process_instance_report import (
|
from spiffworkflow_backend.models.process_instance_report import (
|
||||||
ProcessInstanceReportModel,
|
ProcessInstanceReportModel,
|
||||||
)
|
)
|
||||||
|
from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
||||||
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
|
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.spiff_logging import SpiffLoggingModel
|
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
|
||||||
|
@ -43,6 +44,7 @@ from spiffworkflow_backend.routes.process_api_blueprint import _get_process_mode
|
||||||
from spiffworkflow_backend.routes.process_api_blueprint import (
|
from spiffworkflow_backend.routes.process_api_blueprint import (
|
||||||
_un_modify_modified_process_model_id,
|
_un_modify_modified_process_model_id,
|
||||||
)
|
)
|
||||||
|
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
|
||||||
from spiffworkflow_backend.services.git_service import GitCommandError
|
from spiffworkflow_backend.services.git_service import GitCommandError
|
||||||
from spiffworkflow_backend.services.git_service import GitService
|
from spiffworkflow_backend.services.git_service import GitService
|
||||||
|
@ -88,9 +90,7 @@ def process_instance_run(
|
||||||
do_engine_steps: bool = True,
|
do_engine_steps: bool = True,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_instance_run."""
|
"""Process_instance_run."""
|
||||||
process_instance = ProcessInstanceService().get_process_instance(
|
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||||
process_instance_id
|
|
||||||
)
|
|
||||||
if process_instance.status != "not_started":
|
if process_instance.status != "not_started":
|
||||||
raise ApiError(
|
raise ApiError(
|
||||||
error_code="process_instance_not_runnable",
|
error_code="process_instance_not_runnable",
|
||||||
|
@ -138,9 +138,7 @@ def process_instance_terminate(
|
||||||
modified_process_model_identifier: str,
|
modified_process_model_identifier: str,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_instance_run."""
|
"""Process_instance_run."""
|
||||||
process_instance = ProcessInstanceService().get_process_instance(
|
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||||
process_instance_id
|
|
||||||
)
|
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.terminate()
|
processor.terminate()
|
||||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||||
|
@ -151,9 +149,7 @@ def process_instance_suspend(
|
||||||
modified_process_model_identifier: str,
|
modified_process_model_identifier: str,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_instance_suspend."""
|
"""Process_instance_suspend."""
|
||||||
process_instance = ProcessInstanceService().get_process_instance(
|
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||||
process_instance_id
|
|
||||||
)
|
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.suspend()
|
processor.suspend()
|
||||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||||
|
@ -164,9 +160,7 @@ def process_instance_resume(
|
||||||
modified_process_model_identifier: str,
|
modified_process_model_identifier: str,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_instance_resume."""
|
"""Process_instance_resume."""
|
||||||
process_instance = ProcessInstanceService().get_process_instance(
|
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||||
process_instance_id
|
|
||||||
)
|
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.resume()
|
processor.resume()
|
||||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||||
|
@ -575,14 +569,43 @@ def process_instance_reset(
|
||||||
spiff_step: int = 0,
|
spiff_step: int = 0,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Reset a process instance to a particular step."""
|
"""Reset a process instance to a particular step."""
|
||||||
process_instance = ProcessInstanceService().get_process_instance(
|
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||||
process_instance_id
|
|
||||||
)
|
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.reset_process(spiff_step)
|
processor.reset_process(spiff_step)
|
||||||
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_find_by_id(
|
||||||
|
process_instance_id: int,
|
||||||
|
) -> flask.wrappers.Response:
|
||||||
|
"""Process_instance_find_by_id."""
|
||||||
|
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||||
|
modified_process_model_identifier = (
|
||||||
|
ProcessModelInfo.modify_process_identifier_for_path_param(
|
||||||
|
process_instance.process_model_identifier
|
||||||
|
)
|
||||||
|
)
|
||||||
|
process_instance_uri = (
|
||||||
|
f"/process-instances/{modified_process_model_identifier}/{process_instance.id}"
|
||||||
|
)
|
||||||
|
has_permission = AuthorizationService.user_has_permission(
|
||||||
|
user=g.user,
|
||||||
|
permission="read",
|
||||||
|
target_uri=process_instance_uri,
|
||||||
|
)
|
||||||
|
|
||||||
|
uri_type = None
|
||||||
|
if not has_permission:
|
||||||
|
process_instance = _find_process_instance_for_me_or_raise(process_instance_id)
|
||||||
|
uri_type = "for-me"
|
||||||
|
|
||||||
|
response_json = {
|
||||||
|
"process_instance": process_instance,
|
||||||
|
"uri_type": uri_type,
|
||||||
|
}
|
||||||
|
return make_response(jsonify(response_json), 200)
|
||||||
|
|
||||||
|
|
||||||
def _get_process_instance(
|
def _get_process_instance(
|
||||||
modified_process_model_identifier: str,
|
modified_process_model_identifier: str,
|
||||||
process_instance: ProcessInstanceModel,
|
process_instance: ProcessInstanceModel,
|
||||||
|
|
|
@ -624,6 +624,84 @@ class AuthorizationService:
|
||||||
|
|
||||||
return permissions_to_assign
|
return permissions_to_assign
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_basic_permissions(cls) -> list[PermissionToAssign]:
|
||||||
|
"""Set_basic_permissions."""
|
||||||
|
permissions_to_assign: list[PermissionToAssign] = []
|
||||||
|
permissions_to_assign.append(
|
||||||
|
PermissionToAssign(
|
||||||
|
permission="read", target_uri="/process-instances/for-me"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
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="/user-groups/for-current-user"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
permissions_to_assign.append(
|
||||||
|
PermissionToAssign(
|
||||||
|
permission="read", target_uri="/process-instances/find-by-id/*"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for permission in ["create", "read", "update", "delete"]:
|
||||||
|
permissions_to_assign.append(
|
||||||
|
PermissionToAssign(
|
||||||
|
permission=permission, target_uri="/process-instances/reports/*"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
permissions_to_assign.append(
|
||||||
|
PermissionToAssign(permission=permission, target_uri="/tasks/*")
|
||||||
|
)
|
||||||
|
return permissions_to_assign
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_process_group_permissions(
|
||||||
|
cls, target: str, permission_set: str
|
||||||
|
) -> list[PermissionToAssign]:
|
||||||
|
"""Set_process_group_permissions."""
|
||||||
|
permissions_to_assign: list[PermissionToAssign] = []
|
||||||
|
process_group_identifier = (
|
||||||
|
target.removeprefix("PG:").replace("/", ":").removeprefix(":")
|
||||||
|
)
|
||||||
|
process_related_path_segment = f"{process_group_identifier}:*"
|
||||||
|
if process_group_identifier == "ALL":
|
||||||
|
process_related_path_segment = "*"
|
||||||
|
target_uris = [
|
||||||
|
f"/process-groups/{process_related_path_segment}",
|
||||||
|
f"/process-models/{process_related_path_segment}",
|
||||||
|
]
|
||||||
|
permissions_to_assign = permissions_to_assign + cls.get_permissions_to_assign(
|
||||||
|
permission_set, process_related_path_segment, target_uris
|
||||||
|
)
|
||||||
|
return permissions_to_assign
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_process_model_permissions(
|
||||||
|
cls, target: str, permission_set: str
|
||||||
|
) -> list[PermissionToAssign]:
|
||||||
|
"""Set_process_model_permissions."""
|
||||||
|
permissions_to_assign: list[PermissionToAssign] = []
|
||||||
|
process_model_identifier = (
|
||||||
|
target.removeprefix("PM:").replace("/", ":").removeprefix(":")
|
||||||
|
)
|
||||||
|
process_related_path_segment = f"{process_model_identifier}/*"
|
||||||
|
|
||||||
|
if process_model_identifier == "ALL":
|
||||||
|
process_related_path_segment = "*"
|
||||||
|
|
||||||
|
target_uris = [f"/process-models/{process_related_path_segment}"]
|
||||||
|
permissions_to_assign = permissions_to_assign + cls.get_permissions_to_assign(
|
||||||
|
permission_set, process_related_path_segment, target_uris
|
||||||
|
)
|
||||||
|
return permissions_to_assign
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def explode_permissions(
|
def explode_permissions(
|
||||||
cls, permission_set: str, target: str
|
cls, permission_set: str, target: str
|
||||||
|
@ -654,72 +732,20 @@ class AuthorizationService:
|
||||||
permissions = ["create", "read", "update", "delete"]
|
permissions = ["create", "read", "update", "delete"]
|
||||||
|
|
||||||
if target.startswith("PG:"):
|
if target.startswith("PG:"):
|
||||||
process_group_identifier = (
|
permissions_to_assign += cls.set_process_group_permissions(
|
||||||
target.removeprefix("PG:").replace("/", ":").removeprefix(":")
|
target, permission_set
|
||||||
)
|
)
|
||||||
process_related_path_segment = f"{process_group_identifier}:*"
|
|
||||||
if process_group_identifier == "ALL":
|
|
||||||
process_related_path_segment = "*"
|
|
||||||
target_uris = [
|
|
||||||
f"/process-groups/{process_related_path_segment}",
|
|
||||||
f"/process-models/{process_related_path_segment}",
|
|
||||||
]
|
|
||||||
permissions_to_assign = (
|
|
||||||
permissions_to_assign
|
|
||||||
+ cls.get_permissions_to_assign(
|
|
||||||
permission_set, process_related_path_segment, target_uris
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif target.startswith("PM:"):
|
elif target.startswith("PM:"):
|
||||||
process_model_identifier = (
|
permissions_to_assign += cls.set_process_model_permissions(
|
||||||
target.removeprefix("PM:").replace("/", ":").removeprefix(":")
|
target, permission_set
|
||||||
)
|
)
|
||||||
process_related_path_segment = f"{process_model_identifier}/*"
|
|
||||||
|
|
||||||
if process_model_identifier == "ALL":
|
|
||||||
process_related_path_segment = "*"
|
|
||||||
|
|
||||||
target_uris = [f"/process-models/{process_related_path_segment}"]
|
|
||||||
permissions_to_assign = (
|
|
||||||
permissions_to_assign
|
|
||||||
+ cls.get_permissions_to_assign(
|
|
||||||
permission_set, process_related_path_segment, target_uris
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif permission_set == "start":
|
elif permission_set == "start":
|
||||||
raise InvalidPermissionError(
|
raise InvalidPermissionError(
|
||||||
"Permission 'start' is only available for macros PM and PG."
|
"Permission 'start' is only available for macros PM and PG."
|
||||||
)
|
)
|
||||||
|
|
||||||
elif target.startswith("BASIC"):
|
elif target.startswith("BASIC"):
|
||||||
permissions_to_assign.append(
|
permissions_to_assign += cls.set_basic_permissions()
|
||||||
PermissionToAssign(
|
|
||||||
permission="read", target_uri="/process-instances/for-me"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
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="/user-groups/for-current-user"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for permission in ["create", "read", "update", "delete"]:
|
|
||||||
permissions_to_assign.append(
|
|
||||||
PermissionToAssign(
|
|
||||||
permission=permission, target_uri="/process-instances/reports/*"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
permissions_to_assign.append(
|
|
||||||
PermissionToAssign(permission=permission, target_uri="/tasks/*")
|
|
||||||
)
|
|
||||||
elif target == "ALL":
|
elif target == "ALL":
|
||||||
for permission in permissions:
|
for permission in permissions:
|
||||||
permissions_to_assign.append(
|
permissions_to_assign.append(
|
||||||
|
|
|
@ -354,11 +354,8 @@ class BaseTest:
|
||||||
assert has_permission is expected_result
|
assert has_permission is expected_result
|
||||||
|
|
||||||
def modify_process_identifier_for_path_param(self, identifier: str) -> str:
|
def modify_process_identifier_for_path_param(self, identifier: str) -> str:
|
||||||
"""Identifier."""
|
"""Modify_process_identifier_for_path_param."""
|
||||||
if "\\" in identifier:
|
return ProcessModelInfo.modify_process_identifier_for_path_param(identifier)
|
||||||
raise Exception(f"Found backslash in identifier: {identifier}")
|
|
||||||
|
|
||||||
return identifier.replace("/", ":")
|
|
||||||
|
|
||||||
def un_modify_modified_process_identifier_for_path_param(
|
def un_modify_modified_process_identifier_for_path_param(
|
||||||
self, modified_identifier: str
|
self, modified_identifier: str
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
"""Test_users_controller."""
|
||||||
|
from flask.app import Flask
|
||||||
|
from flask.testing import FlaskClient
|
||||||
|
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||||
|
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||||
|
|
||||||
|
from spiffworkflow_backend.models.user import UserModel
|
||||||
|
|
||||||
|
|
||||||
|
class TestProcessInstancesController(BaseTest):
|
||||||
|
"""TestProcessInstancesController."""
|
||||||
|
|
||||||
|
def test_find_by_id(
|
||||||
|
self,
|
||||||
|
app: Flask,
|
||||||
|
client: FlaskClient,
|
||||||
|
with_db_and_bpmn_file_cleanup: None,
|
||||||
|
with_super_admin_user: UserModel,
|
||||||
|
) -> None:
|
||||||
|
"""Test_user_search_returns_a_user."""
|
||||||
|
user_one = self.create_user_with_permission(
|
||||||
|
username="user_one", target_uri="/process-instances/find-by-id/*"
|
||||||
|
)
|
||||||
|
user_two = self.create_user_with_permission(
|
||||||
|
username="user_two", target_uri="/process-instances/find-by-id/*"
|
||||||
|
)
|
||||||
|
|
||||||
|
process_model = load_test_spec(
|
||||||
|
process_model_id="group/sample",
|
||||||
|
bpmn_file_name="sample.bpmn",
|
||||||
|
process_model_source_directory="sample",
|
||||||
|
)
|
||||||
|
process_instance = self.create_process_instance_from_process_model(
|
||||||
|
process_model=process_model, user=user_one
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f"/v1.0/process-instances/find-by-id/{process_instance.id}",
|
||||||
|
headers=self.logged_in_headers(user_one),
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json
|
||||||
|
assert 'process_instance' in response.json
|
||||||
|
assert response.json['process_instance']["id"] == process_instance.id
|
||||||
|
assert response.json['uri_type'] == 'for-me'
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f"/v1.0/process-instances/find-by-id/{process_instance.id}",
|
||||||
|
headers=self.logged_in_headers(user_two),
|
||||||
|
)
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
f"/v1.0/process-instances/find-by-id/{process_instance.id}",
|
||||||
|
headers=self.logged_in_headers(with_super_admin_user),
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json
|
||||||
|
assert 'process_instance' in response.json
|
||||||
|
assert response.json['process_instance']["id"] == process_instance.id
|
||||||
|
assert response.json['uri_type'] is None
|
|
@ -277,6 +277,7 @@ class TestAuthorizationService(BaseTest):
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test_explode_permissions_basic."""
|
"""Test_explode_permissions_basic."""
|
||||||
expected_permissions = [
|
expected_permissions = [
|
||||||
|
("/process-instances/find-by-id/*", "read"),
|
||||||
("/process-instances/for-me", "read"),
|
("/process-instances/for-me", "read"),
|
||||||
("/process-instances/reports/*", "create"),
|
("/process-instances/reports/*", "create"),
|
||||||
("/process-instances/reports/*", "delete"),
|
("/process-instances/reports/*", "delete"),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
convertSecondsToFormattedDateString,
|
convertSecondsToFormattedDateString,
|
||||||
|
isInteger,
|
||||||
slugifyString,
|
slugifyString,
|
||||||
underscorizeString,
|
underscorizeString,
|
||||||
} from './helpers';
|
} from './helpers';
|
||||||
|
@ -20,3 +21,11 @@ test('it can keep the correct date when converting seconds to date', () => {
|
||||||
const dateString = convertSecondsToFormattedDateString(1666325400);
|
const dateString = convertSecondsToFormattedDateString(1666325400);
|
||||||
expect(dateString).toEqual('2022-10-21');
|
expect(dateString).toEqual('2022-10-21');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it can validate numeric values', () => {
|
||||||
|
expect(isInteger('11')).toEqual(true);
|
||||||
|
expect(isInteger('hey')).toEqual(false);
|
||||||
|
expect(isInteger(' ')).toEqual(false);
|
||||||
|
expect(isInteger('1 2')).toEqual(false);
|
||||||
|
expect(isInteger(2)).toEqual(true);
|
||||||
|
});
|
||||||
|
|
|
@ -253,3 +253,7 @@ export const setErrorMessageSafely = (
|
||||||
errorMessageSetter({ message: newErrorMessageString });
|
errorMessageSetter({ message: newErrorMessageString });
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isInteger = (str: string | number) => {
|
||||||
|
return /^\d+$/.test(str.toString());
|
||||||
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ import MessageInstanceList from './MessageInstanceList';
|
||||||
import Configuration from './Configuration';
|
import Configuration from './Configuration';
|
||||||
import JsonSchemaFormBuilder from './JsonSchemaFormBuilder';
|
import JsonSchemaFormBuilder from './JsonSchemaFormBuilder';
|
||||||
import ProcessModelNewExperimental from './ProcessModelNewExperimental';
|
import ProcessModelNewExperimental from './ProcessModelNewExperimental';
|
||||||
|
import ProcessInstanceFindById from './ProcessInstanceFindById';
|
||||||
|
|
||||||
export default function AdminRoutes() {
|
export default function AdminRoutes() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
@ -133,6 +134,10 @@ export default function AdminRoutes() {
|
||||||
path="process-models/:process_model_id/form-builder"
|
path="process-models/:process_model_id/form-builder"
|
||||||
element={<JsonSchemaFormBuilder />}
|
element={<JsonSchemaFormBuilder />}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="process-instances/find-by-id"
|
||||||
|
element={<ProcessInstanceFindById />}
|
||||||
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
// @ts-ignore
|
||||||
|
import { Button, ButtonSet, Form, Stack, TextInput } from '@carbon/react';
|
||||||
|
import { isInteger, modifyProcessIdentifierForPathParam } from '../helpers';
|
||||||
|
import HttpService from '../services/HttpService';
|
||||||
|
import { ProcessInstance } from '../interfaces';
|
||||||
|
|
||||||
|
export default function ProcessInstanceFindById() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [processInstanceId, setProcessInstanceId] = useState<string>('');
|
||||||
|
const [processInstanceIdValid, setProcessInstanceIdValid] =
|
||||||
|
useState<boolean>(true);
|
||||||
|
|
||||||
|
useEffect(() => {}, []);
|
||||||
|
|
||||||
|
const handleProcessInstanceNavigation = (result: any) => {
|
||||||
|
const processInstance: ProcessInstance = result.process_instance;
|
||||||
|
let path = '/admin/process-instances/';
|
||||||
|
if (result.uri_type === 'for-me') {
|
||||||
|
path += 'for-me/';
|
||||||
|
}
|
||||||
|
path += `${modifyProcessIdentifierForPathParam(
|
||||||
|
processInstance.process_model_identifier
|
||||||
|
)}/${processInstance.id}`;
|
||||||
|
navigate(path);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFormSubmission = (event: any) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (!processInstanceId) {
|
||||||
|
setProcessInstanceIdValid(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (processInstanceId && processInstanceIdValid) {
|
||||||
|
HttpService.makeCallToBackend({
|
||||||
|
path: `/process-instances/find-by-id/${processInstanceId}`,
|
||||||
|
successCallback: handleProcessInstanceNavigation,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProcessInstanceIdChange = (event: any) => {
|
||||||
|
if (isInteger(event.target.value)) {
|
||||||
|
setProcessInstanceIdValid(true);
|
||||||
|
} else {
|
||||||
|
setProcessInstanceIdValid(false);
|
||||||
|
}
|
||||||
|
setProcessInstanceId(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formElements = () => {
|
||||||
|
return (
|
||||||
|
<TextInput
|
||||||
|
id="process-instance-id-input"
|
||||||
|
invalidText="Process Instance Id must be a number."
|
||||||
|
invalid={!processInstanceIdValid}
|
||||||
|
labelText="Process Instance Id*"
|
||||||
|
value={processInstanceId}
|
||||||
|
onChange={handleProcessInstanceIdChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formButtons = () => {
|
||||||
|
const buttons = [<Button type="submit">Submit</Button>];
|
||||||
|
return <ButtonSet>{buttons}</ButtonSet>;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form onSubmit={handleFormSubmission}>
|
||||||
|
<Stack gap={5}>
|
||||||
|
{formElements()}
|
||||||
|
{formButtons()}
|
||||||
|
</Stack>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
|
@ -85,6 +85,15 @@ export default function ProcessInstanceList({ variant }: OwnProps) {
|
||||||
All
|
All
|
||||||
</Tab>
|
</Tab>
|
||||||
</Can>
|
</Can>
|
||||||
|
<Tab
|
||||||
|
title="Search for a process instance by id."
|
||||||
|
data-qa="process-instance-list-find-by-id"
|
||||||
|
onClick={() => {
|
||||||
|
navigate('/admin/process-instances/find-by-id');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Find By Id
|
||||||
|
</Tab>
|
||||||
</TabList>
|
</TabList>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -100,7 +100,7 @@ export default function ProcessModelShow() {
|
||||||
onClose={() => setProcessInstance(null)}
|
onClose={() => setProcessInstance(null)}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
to={`/admin/process-instances/${modifiedProcessModelId}/${processInstance.id}`}
|
to={`/admin/process-instances/for-me/${modifiedProcessModelId}/${processInstance.id}`}
|
||||||
data-qa="process-instance-show-link"
|
data-qa="process-instance-show-link"
|
||||||
>
|
>
|
||||||
view
|
view
|
||||||
|
|
Loading…
Reference in New Issue