Merge pull request #69 from sartography/feature/api_permission_cleanup

Feature/api permission cleanup
This commit is contained in:
Kevin Burnett 2022-12-06 13:13:00 -08:00 committed by GitHub
commit ec11475098
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 342 additions and 214 deletions

View File

@ -338,9 +338,9 @@ paths:
schema:
$ref: "#/components/schemas/ProcessModel"
/process-models/{modified_process_model_id}/files:
/process-models/{modified_process_model_identifier}/files:
parameters:
- name: modified_process_model_id
- name: modified_process_model_identifier
in: path
required: true
description: The process_model_id, modified to replace slashes (/)
@ -565,33 +565,6 @@ paths:
items:
$ref: "#/components/schemas/Workflow"
/process-instances/{process_instance_id}/task/{task_id}/update:
parameters:
- name: process_instance_id
in: path
required: true
description: The unique id of the process instance
schema:
type: string
- name: task_id
in: path
required: true
description: The unique id of the task
schema:
type: string
post:
operationId: spiffworkflow_backend.routes.process_api_blueprint.update_task_data
summary: Update the task data for requested instance and task
tags:
- Process Instances
responses:
"200":
description: Task Updated Successfully
content:
application/json:
schema:
$ref: "#/components/schemas/Workflow"
/process-models/{process_group_id}/{process_model_id}/script-unit-tests:
parameters:
- name: process_group_id
@ -646,15 +619,14 @@ paths:
schema:
$ref: "#/components/schemas/Workflow"
/process-models/{modified_process_model_id}/process-instances:
/process-instances/{modified_process_model_identifier}:
parameters:
- name: modified_process_model_id
- name: modified_process_model_identifier
in: path
required: true
description: The unique id of an existing process model.
schema:
type: string
# process_instance_create
post:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_create
summary: Creates an process instance from a process model and returns the instance
@ -668,28 +640,7 @@ paths:
schema:
$ref: "#/components/schemas/Workflow"
/process-instances/{process_instance_id}:
parameters:
- name: process_instance_id
in: path
required: true
description: The unique id of an existing process instance.
schema:
type: integer
delete:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_delete
summary: Deletes a single process instance
tags:
- Process Instances
responses:
"200":
description: The process instance was deleted.
content:
application/json:
schema:
$ref: "#/components/schemas/OkTrue"
/process-models/{modified_process_model_identifier}/process-instances/{process_instance_id}:
/process-instances/{modified_process_model_identifier}/{process_instance_id}:
parameters:
- name: modified_process_model_identifier
in: path
@ -715,6 +666,18 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Workflow"
delete:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_delete
summary: Deletes a single process instance
tags:
- Process Instances
responses:
"200":
description: The process instance was deleted.
content:
application/json:
schema:
$ref: "#/components/schemas/OkTrue"
/process-instances/{modified_process_model_identifier}/{process_instance_id}/run:
parameters:
@ -743,7 +706,7 @@ paths:
schema:
$ref: "#/components/schemas/Workflow"
/process-instances/{process_instance_id}/terminate:
/process-instances/{modified_process_model_identifier}/{process_instance_id}/terminate:
parameters:
- name: process_instance_id
in: path
@ -764,7 +727,7 @@ paths:
schema:
$ref: "#/components/schemas/OkTrue"
/process-instances/{process_instance_id}/suspend:
/process-instances/{modified_process_model_identifier}/{process_instance_id}/suspend:
parameters:
- name: process_instance_id
in: path
@ -785,7 +748,7 @@ paths:
schema:
$ref: "#/components/schemas/OkTrue"
/process-instances/{process_instance_id}/resume:
/process-instances/{modified_process_model_identifier}/{process_instance_id}/resume:
parameters:
- name: process_instance_id
in: path
@ -922,9 +885,9 @@ paths:
schema:
$ref: "#/components/schemas/OkTrue"
/process-models/{modified_process_model_id}/files/{file_name}:
/process-models/{modified_process_model_identifier}/files/{file_name}:
parameters:
- name: modified_process_model_id
- name: modified_process_model_identifier
in: path
required: true
description: The modified process model id
@ -1101,9 +1064,9 @@ paths:
items:
$ref: "#/components/schemas/Task"
/process-instances/{modified_process_model_id}/{process_instance_id}/tasks:
/task-data/{modified_process_model_identifier}/{process_instance_id}:
parameters:
- name: modified_process_model_id
- name: modified_process_model_identifier
in: path
required: true
description: The modified id of an existing process model
@ -1142,11 +1105,44 @@ paths:
items:
$ref: "#/components/schemas/Task"
/service_tasks:
/task-data/{modified_process_model_identifier}/{process_instance_id}/{task_id}:
parameters:
- name: modified_process_model_identifier
in: path
required: true
description: The modified id of an existing process model
schema:
type: string
- name: process_instance_id
in: path
required: true
description: The unique id of an existing process instance.
schema:
type: integer
- name: task_id
in: path
required: true
description: The unique id of the task.
schema:
type: string
put:
operationId: spiffworkflow_backend.routes.process_api_blueprint.update_task_data
summary: Update the task data for requested instance and task
tags:
- Process Instances
responses:
"200":
description: Task Updated Successfully
content:
application/json:
schema:
$ref: "#/components/schemas/Workflow"
/service-tasks:
get:
tags:
- Service Tasks
operationId: spiffworkflow_backend.routes.process_api_blueprint.service_tasks_show
operationId: spiffworkflow_backend.routes.process_api_blueprint.service_task_list
summary: Gets all available service task connectors
responses:
"200":
@ -1326,7 +1322,7 @@ paths:
schema:
$ref: "#/components/schemas/Workflow"
/process-instances/{process_instance_id}/logs:
/logs/{modified_process_model_identifier}/{process_instance_id}:
parameters:
- name: process_instance_id
in: path
@ -1346,6 +1342,12 @@ paths:
description: The number of items to show per page. Defaults to page 10.
schema:
type: integer
- name: detailed
in: query
required: false
description: Show the detailed view, which includes all log entries
schema:
type: boolean
get:
tags:
- Process Instances

View File

@ -12,7 +12,6 @@ groups:
mike,
jason,
j,
amir,
jarrad,
elizabeth,
jon,
@ -70,6 +69,12 @@ permissions:
users: []
allowed_permissions: [create, read, update, delete]
uri: /v1.0/tasks/*
service-tasks:
groups: [everybody]
users: []
allowed_permissions: [read]
uri: /v1.0/service-tasks
# read all for everybody
read-all-process-groups:
@ -98,6 +103,12 @@ permissions:
allowed_permissions: [read]
uri: /v1.0/processes
task-data-read:
groups: [demo]
users: []
allowed_permissions: [read]
uri: /v1.0/task-data/*
manage-procurement-admin:
groups: ["Project Lead"]
@ -170,17 +181,17 @@ permissions:
uri: /v1.0/process-instances/manage-procurement:vendor-lifecycle-management:*
core1-admin-models-instantiate:
groups: ["core-contributor"]
groups: ["core-contributor", "Finance Team"]
users: []
allowed_permissions: [create]
uri: /v1.0/process-models/misc:category_number_one:process-model-with-form/process-instances
core1-admin-instances:
groups: ["core-contributor"]
groups: ["core-contributor", "Finance Team"]
users: []
allowed_permissions: [create, read]
uri: /v1.0/process-instances/misc:category_number_one:process-model-with-form:*
core1-admin-instances-slash:
groups: ["core-contributor"]
groups: ["core-contributor", "Finance Team"]
users: []
allowed_permissions: [create, read]
uri: /v1.0/process-instances/misc:category_number_one:process-model-with-form/*

View File

@ -12,7 +12,6 @@ groups:
mike,
jason,
j,
amir,
jarrad,
elizabeth,
jon,
@ -98,6 +97,12 @@ permissions:
allowed_permissions: [read]
uri: /v1.0/processes
task-data-read:
groups: [demo]
users: []
allowed_permissions: [read]
uri: /v1.0/task-data/*
manage-procurement-admin:
groups: ["Project Lead"]

View File

@ -158,9 +158,9 @@ def modify_process_model_id(process_model_id: str) -> str:
return process_model_id.replace("/", ":")
def un_modify_modified_process_model_id(modified_process_model_id: str) -> str:
def un_modify_modified_process_model_id(modified_process_model_identifier: str) -> str:
"""Un_modify_modified_process_model_id."""
return modified_process_model_id.replace(":", "/")
return modified_process_model_identifier.replace(":", "/")
def process_group_add(body: dict) -> flask.wrappers.Response:
@ -411,9 +411,9 @@ def process_list() -> Any:
return SpecReferenceSchema(many=True).dump(references)
def get_file(modified_process_model_id: str, file_name: str) -> Any:
def get_file(modified_process_model_identifier: str, file_name: str) -> Any:
"""Get_file."""
process_model_identifier = modified_process_model_id.replace(":", "/")
process_model_identifier = modified_process_model_identifier.replace(":", "/")
process_model = get_process_model(process_model_identifier)
files = SpecFileService.get_files(process_model, file_name)
if len(files) == 0:
@ -433,10 +433,10 @@ def get_file(modified_process_model_id: str, file_name: str) -> Any:
def process_model_file_update(
modified_process_model_id: str, file_name: str
modified_process_model_identifier: str, file_name: str
) -> flask.wrappers.Response:
"""Process_model_file_update."""
process_model_identifier = modified_process_model_id.replace(":", "/")
process_model_identifier = modified_process_model_identifier.replace(":", "/")
process_model = get_process_model(process_model_identifier)
request_file = get_file_from_request()
@ -462,10 +462,10 @@ def process_model_file_update(
def process_model_file_delete(
modified_process_model_id: str, file_name: str
modified_process_model_identifier: str, file_name: str
) -> flask.wrappers.Response:
"""Process_model_file_delete."""
process_model_identifier = modified_process_model_id.replace(":", "/")
process_model_identifier = modified_process_model_identifier.replace(":", "/")
process_model = get_process_model(process_model_identifier)
try:
SpecFileService.delete_file(process_model, file_name)
@ -481,9 +481,9 @@ def process_model_file_delete(
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
def add_file(modified_process_model_id: str) -> flask.wrappers.Response:
def add_file(modified_process_model_identifier: str) -> flask.wrappers.Response:
"""Add_file."""
process_model_identifier = modified_process_model_id.replace(":", "/")
process_model_identifier = modified_process_model_identifier.replace(":", "/")
process_model = get_process_model(process_model_identifier)
request_file = get_file_from_request()
if not request_file.filename:
@ -504,10 +504,12 @@ def add_file(modified_process_model_id: str) -> flask.wrappers.Response:
)
def process_instance_create(modified_process_model_id: str) -> flask.wrappers.Response:
def process_instance_create(
modified_process_model_identifier: str,
) -> flask.wrappers.Response:
"""Create_process_instance."""
process_model_identifier = un_modify_modified_process_model_id(
modified_process_model_id
modified_process_model_identifier
)
process_instance = (
ProcessInstanceService.create_process_instance_from_process_model_identifier(
@ -565,6 +567,7 @@ def process_instance_run(
def process_instance_terminate(
process_instance_id: int,
modified_process_model_identifier: str,
) -> flask.wrappers.Response:
"""Process_instance_run."""
process_instance = ProcessInstanceService().get_process_instance(
@ -577,6 +580,7 @@ def process_instance_terminate(
def process_instance_suspend(
process_instance_id: int,
modified_process_model_identifier: str,
) -> flask.wrappers.Response:
"""Process_instance_suspend."""
process_instance = ProcessInstanceService().get_process_instance(
@ -589,6 +593,7 @@ def process_instance_suspend(
def process_instance_resume(
process_instance_id: int,
modified_process_model_identifier: str,
) -> flask.wrappers.Response:
"""Process_instance_resume."""
process_instance = ProcessInstanceService().get_process_instance(
@ -600,19 +605,24 @@ def process_instance_resume(
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 = SpiffLoggingModel.query.filter(
SpiffLoggingModel.process_instance_id == process_instance.id
)
if not detailed:
log_query = log_query.filter(SpiffLoggingModel.message.in_(["State change to COMPLETED"])) # type: ignore
logs = (
SpiffLoggingModel.query.filter(
SpiffLoggingModel.process_instance_id == process_instance.id
)
.order_by(SpiffLoggingModel.timestamp.desc()) # type: ignore
log_query.order_by(SpiffLoggingModel.timestamp.desc()) # type: ignore
.join(
UserModel, UserModel.id == SpiffLoggingModel.current_user_id, isouter=True
) # isouter since if we don't have a user, we still want the log
@ -1071,7 +1081,9 @@ def process_instance_show(
return make_response(jsonify(process_instance), 200)
def process_instance_delete(process_instance_id: int) -> flask.wrappers.Response:
def process_instance_delete(
process_instance_id: int, modified_process_model_identifier: str
) -> flask.wrappers.Response:
"""Create_process_instance."""
process_instance = find_process_instance_by_id_or_raise(process_instance_id)
@ -1153,8 +1165,8 @@ def process_instance_report_delete(
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
def service_tasks_show() -> flask.wrappers.Response:
"""Service_tasks_show."""
def service_task_list() -> flask.wrappers.Response:
"""Service_task_list."""
available_connectors = ServiceTaskService.available_connectors()
return Response(
json.dumps(available_connectors), status=200, mimetype="application/json"
@ -1361,7 +1373,7 @@ def get_tasks(
def process_instance_task_list(
modified_process_model_id: str,
modified_process_model_identifier: str,
process_instance_id: int,
all_tasks: bool = False,
spiff_step: int = 0,
@ -1922,7 +1934,12 @@ def _update_form_schema_with_task_data_as_needed(
_update_form_schema_with_task_data_as_needed(o, task_data)
def update_task_data(process_instance_id: str, task_id: str, body: Dict) -> Response:
def update_task_data(
process_instance_id: str,
modified_process_model_identifier: str,
task_id: str,
body: Dict,
) -> Response:
"""Update task data."""
process_instance = ProcessInstanceModel.query.filter(
ProcessInstanceModel.id == int(process_instance_id)

View File

@ -265,7 +265,7 @@ class BaseTest:
)
modified_process_model_id = test_process_model_id.replace("/", ":")
response = client.post(
f"/v1.0/process-models/{modified_process_model_id}/process-instances",
f"/v1.0/process-instances/{modified_process_model_id}",
headers=headers,
)
assert response.status_code == 201

View File

@ -57,7 +57,7 @@ class TestLoggingService(BaseTest):
assert response.status_code == 200
log_response = client.get(
f"/v1.0/process-instances/{process_instance_id}/logs",
f"/v1.0/logs/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}",
headers=headers,
)
assert log_response.status_code == 200

View File

@ -912,7 +912,7 @@ class TestProcessApi(BaseTest):
modified_process_model_identifier = process_model_identifier.replace("/", ":")
response = client.post(
f"/v1.0/process-models/{modified_process_model_identifier}/process-instances",
f"/v1.0/process-instances/{modified_process_model_identifier}",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 201
@ -1154,10 +1154,11 @@ class TestProcessApi(BaseTest):
headers=self.logged_in_headers(with_super_admin_user),
)
show_response = client.get(
f"/v1.0/process-models/{modified_process_model_identifier}/process-instances/{process_instance_id}",
f"/v1.0/process-instances/{modified_process_model_identifier}/{process_instance_id}",
headers=self.logged_in_headers(with_super_admin_user),
)
assert show_response.json is not None
assert show_response.status_code == 200
file_system_root = FileSystemService.root_path()
file_path = (
f"{file_system_root}/{process_model_identifier}/{process_model_id}.bpmn"
@ -1320,7 +1321,7 @@ class TestProcessApi(BaseTest):
assert response.json is not None
response = client.post(
f"/v1.0/process-instances/{process_instance_id}/terminate",
f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}/terminate",
headers=self.logged_in_headers(with_super_admin_user),
)
assert response.status_code == 200
@ -1367,7 +1368,7 @@ class TestProcessApi(BaseTest):
assert response.json is not None
delete_response = client.delete(
f"/v1.0/process-instances/{process_instance_id}",
f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}",
headers=self.logged_in_headers(with_super_admin_user),
)
assert delete_response.status_code == 200
@ -2366,7 +2367,7 @@ class TestProcessApi(BaseTest):
assert process_instance.status == "user_input_required"
client.post(
f"/v1.0/process-instances/{process_instance_id}/suspend",
f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}/suspend",
headers=self.logged_in_headers(with_super_admin_user),
)
process_instance = ProcessInstanceService().get_process_instance(

View File

@ -372,15 +372,18 @@ export default function ProcessInstanceListTable({
titleOperation = 'Created';
}
return (
<InlineNotification
title={`Perspective ${titleOperation}:`}
subtitle={`'${
processInstanceReportSelection
? processInstanceReportSelection.identifier
: ''
}'`}
kind="success"
/>
<>
<InlineNotification
title={`Perspective ${titleOperation}:`}
subtitle={`'${
processInstanceReportSelection
? processInstanceReportSelection.identifier
: ''
}'`}
kind="success"
/>
<br />
</>
);
}
return null;
@ -935,6 +938,15 @@ export default function ProcessInstanceListTable({
if (!showFilterOptions) {
return null;
}
// get the columns anytime we display the filter options if they are empty
if (availableReportColumns.length < 1) {
HttpService.makeCallToBackend({
path: `/process-instances/reports/columns`,
successCallback: setAvailableReportColumns,
});
}
return (
<>
<Grid fullWidth className="with-bottom-margin">
@ -1059,7 +1071,7 @@ export default function ProcessInstanceListTable({
return (
<Link
data-qa="process-instance-show-link"
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${id}`}
to={`/admin/process-instances/${modifiedProcessModelId}/${id}`}
title={`View process instance ${id}`}
>
{id}
@ -1134,10 +1146,6 @@ export default function ProcessInstanceListTable({
const toggleShowFilterOptions = () => {
setShowFilterOptions(!showFilterOptions);
HttpService.makeCallToBackend({
path: `/process-instances/reports/columns`,
successCallback: setAvailableReportColumns,
});
};
const reportSearchComponent = () => {
@ -1166,6 +1174,9 @@ export default function ProcessInstanceListTable({
return (
<>
<Grid fullWidth>
<Column sm={2} md={4} lg={7}>
{reportSearchComponent()}
</Column>
<Column
className="filterIcon"
sm={{ span: 1, offset: 3 }}
@ -1204,7 +1215,6 @@ export default function ProcessInstanceListTable({
{reportColumnForm()}
{processInstanceReportSaveTag()}
{filterComponent()}
{reportSearchComponent()}
<PaginationForTable
page={page}
perPage={perPage}

View File

@ -83,9 +83,9 @@ export default function ProcessInstanceRun({
processModel.id
);
const processInstanceActionPath = `/v1.0/process-models/${modifiedProcessModelId}/process-instances`;
const processInstanceCreatePath = `/v1.0/process-instances/${modifiedProcessModelId}`;
let permissionRequestData: PermissionsToCheck = {
[processInstanceActionPath]: ['POST'],
[processInstanceCreatePath]: ['POST'],
};
if (!checkPermissions) {
@ -117,14 +117,14 @@ export default function ProcessInstanceRun({
const processInstanceCreateAndRun = () => {
HttpService.makeCallToBackend({
path: processInstanceActionPath,
path: processInstanceCreatePath,
successCallback: processModelRun,
httpMethod: 'POST',
});
};
if (checkPermissions) {
return (
<Can I="POST" a={processInstanceActionPath} ability={ability}>
<Can I="POST" a={processInstanceCreatePath} ability={ability}>
<Button onClick={processInstanceCreateAndRun} className={className}>
Start
</Button>

View File

@ -194,7 +194,6 @@ export default function ProcessModelForm({
onChange={(event: any) => {
onDisplayNameChanged(event.target.value);
}}
onBlur={(event: any) => console.log('event', event)}
/>,
];

View File

@ -54,9 +54,9 @@ export default function ProcessModelListTiles({
<p>
Process Instance {processInstance.id} kicked off (
<Link
to={`/admin/process-models/${modifyProcessIdentifierForPathParam(
to={`/admin/process-instances/${modifyProcessIdentifierForPathParam(
processInstance.process_model_identifier
)}/process-instances/${processInstance.id}`}
)}/${processInstance.id}`}
data-qa="process-instance-show-link"
>
view

View File

@ -55,7 +55,7 @@ export default function MyOpenProcesses() {
<td>
<Link
data-qa="process-instance-show-link"
to={`/admin/process-models/${modifiedProcessModelIdentifier}/process-instances/${rowToUse.process_instance_id}`}
to={`/admin/process-instances/${modifiedProcessModelIdentifier}/${rowToUse.process_instance_id}`}
title={`View process instance ${rowToUse.process_instance_id}`}
>
{rowToUse.process_instance_id}

View File

@ -47,7 +47,7 @@ export default function TasksWaitingForMe() {
<td>
<Link
data-qa="process-instance-show-link"
to={`/admin/process-models/${modifiedProcessModelIdentifier}/process-instances/${rowToUse.process_instance_id}`}
to={`/admin/${modifiedProcessModelIdentifier}/${rowToUse.process_instance_id}`}
title={`View process instance ${rowToUse.process_instance_id}`}
>
{rowToUse.process_instance_id}

View File

@ -55,7 +55,7 @@ export default function TasksWaitingForMyGroups() {
<td>
<Link
data-qa="process-instance-show-link"
to={`/admin/process-models/${modifiedProcessModelIdentifier}/process-instances/${rowToUse.process_instance_id}`}
to={`/admin/process-instances/${modifiedProcessModelIdentifier}/${rowToUse.process_instance_id}`}
title={`View process instance ${rowToUse.process_instance_id}`}
>
{rowToUse.process_instance_id}

View File

@ -9,10 +9,12 @@ export const useUriListForPermissions = () => {
messageInstanceListPath: '/v1.0/messages',
processGroupListPath: '/v1.0/process-groups',
processGroupShowPath: `/v1.0/process-groups/${params.process_group_id}`,
processInstanceActionPath: `/v1.0/process-models/${params.process_model_id}/process-instances`,
processInstanceCreatePath: `/v1.0/process-instances/${params.process_model_id}`,
processInstanceActionPath: `/v1.0/process-instances/${params.process_model_id}/${params.process_instance_id}`,
processInstanceListPath: '/v1.0/process-instances',
processInstanceTaskListPath: `/v1.0/process-instances/${params.process_model_id}/${params.process_instance_id}/tasks`,
processInstanceLogListPath: `/v1.0/logs/${params.process_model_id}/${params.process_instance_id}`,
processInstanceReportListPath: '/v1.0/process-instances/reports',
processInstanceTaskListPath: `/v1.0/task-data/${params.process_model_id}/${params.process_instance_id}`,
processModelCreatePath: `/v1.0/process-models/${params.process_group_id}`,
processModelFileCreatePath: `/v1.0/process-models/${params.process_model_id}/files`,
processModelFileShowPath: `/v1.0/process-models/${params.process_model_id}/files/${params.file_name}`,

View File

@ -71,11 +71,11 @@ export default function AdminRoutes() {
element={<ProcessModelEdit />}
/>
<Route
path="process-models/:process_model_id/process-instances/:process_instance_id"
path="process-instances/:process_model_id/:process_instance_id"
element={<ProcessInstanceShow />}
/>
<Route
path="process-models/:process_model_id/process-instances/:process_instance_id/:spiff_step"
path="process-instances/:process_model_id/:process_instance_id/:spiff_step"
element={<ProcessInstanceShow />}
/>
<Route
@ -103,7 +103,7 @@ export default function AdminRoutes() {
element={<ReactFormEditor />}
/>
<Route
path="process-models/:process_model_id/process-instances/:process_instance_id/logs"
path="logs/:process_model_id/:process_instance_id"
element={<ProcessInstanceLogList />}
/>
<Route path="process-instances" element={<ProcessInstanceList />} />

View File

@ -102,9 +102,9 @@ export default function MessageInstanceList() {
<td>
<Link
data-qa="process-instance-show-link"
to={`/admin/process-models/${modifyProcessIdentifierForPathParam(
to={`/admin/process-instances/${modifyProcessIdentifierForPathParam(
row.process_model_identifier
)}/process-instances/${row.process_instance_id}`}
)}/${row.process_instance_id}`}
>
{row.process_instance_id}
</Link>
@ -163,9 +163,9 @@ export default function MessageInstanceList() {
},
[
`Process Instance: ${searchParams.get('process_instance_id')}`,
`/admin/process-models/${searchParams.get(
`/admin/process-instances/${searchParams.get(
'process_model_id'
)}/process-instances/${searchParams.get('process_instance_id')}`,
)}/${searchParams.get('process_instance_id')}`,
],
['Messages'],
]}

View File

@ -55,9 +55,9 @@ export default function MyTasks() {
<p>
Process Instance {processInstance.id} kicked off (
<Link
to={`/admin/process-models/${modifyProcessIdentifierForPathParam(
to={`/admin/process-instances/${modifyProcessIdentifierForPathParam(
processInstance.process_model_identifier
)}/process-instances/${processInstance.id}`}
)}/${processInstance.id}`}
data-qa="process-instance-show-link"
>
view
@ -95,7 +95,7 @@ export default function MyTasks() {
<td>
<Link
data-qa="process-instance-show-link"
to={`/admin/process-models/${modifiedProcessModelIdentifier}/process-instances/${rowToUse.process_instance_id}`}
to={`/admin/process-instances/${modifiedProcessModelIdentifier}/${rowToUse.process_instance_id}`}
>
{rowToUse.process_instance_id}
</Link>

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
// @ts-ignore
import { Table } from '@carbon/react';
import { Table, Tabs, TabList, Tab } from '@carbon/react';
import { useParams, useSearchParams, Link } from 'react-router-dom';
import PaginationForTable from '../components/PaginationForTable';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
@ -10,15 +10,18 @@ import {
convertSecondsToFormattedDateTime,
} from '../helpers';
import HttpService from '../services/HttpService';
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
export default function ProcessInstanceLogList() {
const params = useParams();
const [searchParams] = useSearchParams();
const [searchParams, setSearchParams] = useSearchParams();
const [processInstanceLogs, setProcessInstanceLogs] = useState([]);
const [pagination, setPagination] = useState(null);
const modifiedProcessModelId = modifyProcessIdentifierForPathParam(
`${params.process_model_id}`
);
const { targetUris } = useUriListForPermissions();
const isDetailedView = searchParams.get('detailed') === 'true';
useEffect(() => {
const setProcessInstanceLogListFromResult = (result: any) => {
@ -27,26 +30,36 @@ export default function ProcessInstanceLogList() {
};
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
HttpService.makeCallToBackend({
path: `/process-instances/${params.process_instance_id}/logs?per_page=${perPage}&page=${page}`,
path: `${targetUris.processInstanceLogListPath}?per_page=${perPage}&page=${page}&detailed=${isDetailedView}`,
successCallback: setProcessInstanceLogListFromResult,
});
}, [searchParams, params]);
}, [
searchParams,
params,
targetUris.processInstanceLogListPath,
isDetailedView,
]);
const buildTable = () => {
const rows = processInstanceLogs.map((row) => {
const rowToUse = row as any;
return (
<tr key={rowToUse.id}>
<td>{rowToUse.bpmn_process_identifier}</td>
<td>{rowToUse.id}</td>
<td>{rowToUse.message}</td>
<td>{rowToUse.bpmn_task_identifier}</td>
<td>{rowToUse.bpmn_task_name}</td>
<td>{rowToUse.bpmn_task_type}</td>
{isDetailedView && (
<>
<td>{rowToUse.bpmn_task_identifier}</td>
<td>{rowToUse.bpmn_task_type}</td>
<td>{rowToUse.bpmn_process_identifier}</td>
</>
)}
<td>{rowToUse.username}</td>
<td>
<Link
data-qa="process-instance-show-link"
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${rowToUse.process_instance_id}/${rowToUse.spiff_step}`}
to={`/admin/process-instances/${modifiedProcessModelId}/${rowToUse.process_instance_id}/${rowToUse.spiff_step}`}
>
{convertSecondsToFormattedDateTime(rowToUse.timestamp)}
</Link>
@ -58,11 +71,16 @@ export default function ProcessInstanceLogList() {
<Table size="lg">
<thead>
<tr>
<th>Bpmn Process Identifier</th>
<th>Id</th>
<th>Message</th>
<th>Task Identifier</th>
<th>Task Name</th>
<th>Task Type</th>
{isDetailedView && (
<>
<th>Task Identifier</th>
<th>Task Type</th>
<th>Bpmn Process Identifier</th>
</>
)}
<th>User</th>
<th>Timestamp</th>
</tr>
@ -71,11 +89,12 @@ export default function ProcessInstanceLogList() {
</Table>
);
};
const selectedTabIndex = isDetailedView ? 1 : 0;
if (pagination) {
const { page, perPage } = getPageInfoFromSearchParams(searchParams);
return (
<main>
<>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
@ -86,18 +105,41 @@ export default function ProcessInstanceLogList() {
},
[
`Process Instance: ${params.process_instance_id}`,
`/admin/process-models/${params.process_model_id}/process-instances/${params.process_instance_id}`,
`/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`,
],
['Logs'],
]}
/>
<Tabs selectedIndex={selectedTabIndex}>
<TabList aria-label="List of tabs">
<Tab
title="Only show a subset of the logs, and show fewer columns"
onClick={() => {
searchParams.set('detailed', 'false');
setSearchParams(searchParams);
}}
>
Simple
</Tab>
<Tab
title="Show all logs for this process instance, and show extra columns that may be useful for debugging"
onClick={() => {
searchParams.set('detailed', 'true');
setSearchParams(searchParams);
}}
>
Detailed
</Tab>
</TabList>
</Tabs>
<br />
<PaginationForTable
page={page}
perPage={perPage}
pagination={pagination}
tableToDisplay={buildTable()}
/>
</main>
</>
);
}
return null;

View File

@ -59,6 +59,11 @@ export default function ProcessInstanceShow() {
const permissionRequestData: PermissionsToCheck = {
[targetUris.messageInstanceListPath]: ['GET'],
[targetUris.processInstanceTaskListPath]: ['GET'],
[targetUris.processInstanceActionPath]: ['DELETE'],
[targetUris.processInstanceLogListPath]: ['GET'],
[`${targetUris.processInstanceActionPath}/suspend`]: ['PUT'],
[`${targetUris.processInstanceActionPath}/terminate`]: ['PUT'],
[`${targetUris.processInstanceActionPath}/resume`]: ['PUT'],
};
const { ability, permissionsLoaded } = usePermissionFetcher(
permissionRequestData
@ -76,7 +81,7 @@ export default function ProcessInstanceShow() {
setTasksCallHadError(true);
};
HttpService.makeCallToBackend({
path: `/process-models/${modifiedProcessModelId}/process-instances/${params.process_instance_id}`,
path: `/process-instances/${modifiedProcessModelId}/${params.process_instance_id}`,
successCallback: setProcessInstance,
});
let taskParams = '?all_tasks=true';
@ -85,7 +90,7 @@ export default function ProcessInstanceShow() {
}
if (ability.can('GET', targetUris.processInstanceTaskListPath)) {
HttpService.makeCallToBackend({
path: `/process-instances/${modifiedProcessModelId}/${params.process_instance_id}/tasks${taskParams}`,
path: `${targetUris.processInstanceTaskListPath}${taskParams}`,
successCallback: setTasks,
failureCallback: processTaskFailure,
});
@ -97,7 +102,7 @@ export default function ProcessInstanceShow() {
const deleteProcessInstance = () => {
HttpService.makeCallToBackend({
path: `/process-instances/${params.process_instance_id}`,
path: targetUris.processInstanceActionPath,
successCallback: navigateToProcessInstances,
httpMethod: 'DELETE',
});
@ -110,7 +115,7 @@ export default function ProcessInstanceShow() {
const terminateProcessInstance = () => {
HttpService.makeCallToBackend({
path: `/process-instances/${params.process_instance_id}/terminate`,
path: `${targetUris.processInstanceActionPath}/terminate`,
successCallback: refreshPage,
httpMethod: 'POST',
});
@ -118,7 +123,7 @@ export default function ProcessInstanceShow() {
const suspendProcessInstance = () => {
HttpService.makeCallToBackend({
path: `/process-instances/${params.process_instance_id}/suspend`,
path: `${targetUris.processInstanceActionPath}/suspend`,
successCallback: refreshPage,
httpMethod: 'POST',
});
@ -126,7 +131,7 @@ export default function ProcessInstanceShow() {
const resumeProcessInstance = () => {
HttpService.makeCallToBackend({
path: `/process-instances/${params.process_instance_id}/resume`,
path: `${targetUris.processInstanceActionPath}/resume`,
successCallback: refreshPage,
httpMethod: 'POST',
});
@ -174,7 +179,7 @@ export default function ProcessInstanceShow() {
<Link
reloadDocument
data-qa="process-instance-step-link"
to={`/admin/process-models/${
to={`/admin/process-instances/${
params.process_model_id
}/process-instances/${params.process_instance_id}/${
currentSpiffStep(processInstanceToUse) + distance
@ -209,7 +214,7 @@ export default function ProcessInstanceShow() {
if (currentEndDate) {
currentEndDateTag = (
<Grid condensed fullWidth>
<Column sm={1} md={1} lg={1} className="grid-list-title">
<Column sm={1} md={1} lg={2} className="grid-list-title">
Completed:{' '}
</Column>
<Column sm={3} md={3} lg={3} className="grid-date">
@ -235,7 +240,7 @@ export default function ProcessInstanceShow() {
return (
<>
<Grid condensed fullWidth>
<Column sm={1} md={1} lg={1} className="grid-list-title">
<Column sm={1} md={1} lg={2} className="grid-list-title">
Started:{' '}
</Column>
<Column sm={3} md={3} lg={3} className="grid-date">
@ -246,7 +251,7 @@ export default function ProcessInstanceShow() {
</Grid>
{currentEndDateTag}
<Grid condensed fullWidth>
<Column sm={1} md={1} lg={1} className="grid-list-title">
<Column sm={1} md={1} lg={2} className="grid-list-title">
Status:{' '}
</Column>
<Column sm={3} md={3} lg={3}>
@ -259,14 +264,20 @@ export default function ProcessInstanceShow() {
<Grid condensed fullWidth>
<Column sm={2} md={2} lg={2}>
<ButtonSet>
<Button
size="sm"
className="button-white-background"
data-qa="process-instance-log-list-link"
href={`/admin/process-models/${modifiedProcessModelId}/process-instances/${params.process_instance_id}/logs`}
<Can
I="GET"
a={targetUris.processInstanceLogListPath}
ability={ability}
>
Logs
</Button>
<Button
size="sm"
className="button-white-background"
data-qa="process-instance-log-list-link"
href={`/admin/logs/${modifiedProcessModelId}/${params.process_instance_id}`}
>
Logs
</Button>
</Can>
<Can
I="GET"
a={targetUris.messageInstanceListPath}
@ -436,8 +447,8 @@ export default function ProcessInstanceShow() {
// taskToUse is copy of taskToDisplay, with taskDataToDisplay in data attribute
const taskToUse: any = { ...taskToDisplay, data: taskDataToDisplay };
HttpService.makeCallToBackend({
path: `/process-instances/${params.process_instance_id}/task/${taskToUse.id}/update`,
httpMethod: 'POST',
path: `/task-data/${modifiedProcessModelId}/${params.process_instance_id}/${taskToUse.id}`,
httpMethod: 'PUT',
successCallback: saveTaskDataResult,
failureCallback: saveTaskDataFailure,
postBody: {
@ -544,21 +555,33 @@ export default function ProcessInstanceShow() {
const buttonIcons = (processInstanceToUse: any) => {
const elements = [];
elements.push(terminateButton(processInstanceToUse));
elements.push(suspendButton(processInstanceToUse));
elements.push(resumeButton(processInstanceToUse));
elements.push(
<ButtonWithConfirmation
data-qa="process-instance-delete"
kind="ghost"
renderIcon={TrashCan}
iconDescription="Delete"
hasIconOnly
description={`Delete Process Instance: ${processInstanceToUse.id}`}
onConfirmation={deleteProcessInstance}
confirmButtonLabel="Delete"
/>
);
if (
ability.can('POST', `${targetUris.processInstanceActionPath}/terminate`)
) {
elements.push(terminateButton(processInstanceToUse));
}
if (
ability.can('POST', `${targetUris.processInstanceActionPath}/suspend`)
) {
elements.push(suspendButton(processInstanceToUse));
}
if (ability.can('POST', `${targetUris.processInstanceActionPath}/resume`)) {
elements.push(resumeButton(processInstanceToUse));
}
if (ability.can('DELETE', targetUris.processInstanceActionPath)) {
elements.push(
<ButtonWithConfirmation
data-qa="process-instance-delete"
kind="ghost"
renderIcon={TrashCan}
iconDescription="Delete"
hasIconOnly
description={`Delete Process Instance: ${processInstanceToUse.id}`}
onConfirmation={deleteProcessInstance}
confirmButtonLabel="Delete"
/>
);
}
return elements;
};

View File

@ -283,7 +283,7 @@ export default function ProcessModelEditDiagram() {
const onServiceTasksRequested = (event: any) => {
HttpService.makeCallToBackend({
path: `/service_tasks`,
path: `/service-tasks`,
successCallback: makeApiHandler(event),
});
};

View File

@ -66,7 +66,7 @@ export default function ProcessModelShow() {
const permissionRequestData: PermissionsToCheck = {
[targetUris.processModelShowPath]: ['PUT', 'DELETE'],
[targetUris.processInstanceListPath]: ['GET'],
[targetUris.processInstanceActionPath]: ['POST'],
[targetUris.processInstanceCreatePath]: ['POST'],
[targetUris.processModelFileCreatePath]: ['POST', 'PUT', 'GET', 'DELETE'],
};
const { ability, permissionsLoaded } = usePermissionFetcher(
@ -95,7 +95,7 @@ export default function ProcessModelShow() {
<p>
Process Instance {processInstance.id} kicked off (
<Link
to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${processInstance.id}`}
to={`/admin/process-instances/${modifiedProcessModelId}/${processInstance.id}`}
data-qa="process-instance-show-link"
>
view
@ -556,7 +556,7 @@ export default function ProcessModelShow() {
<Stack orientation="horizontal" gap={3}>
<Can
I="POST"
a={targetUris.processInstanceActionPath}
a={targetUris.processInstanceCreatePath}
ability={ability}
>
<>

View File

@ -26,6 +26,9 @@ import Form from '../themes/carbon';
import HttpService from '../services/HttpService';
import ErrorContext from '../contexts/ErrorContext';
import { modifyProcessIdentifierForPathParam } from '../helpers';
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
import { PermissionsToCheck } from '../interfaces';
import { usePermissionFetcher } from '../hooks/PermissionService';
export default function TaskShow() {
const [task, setTask] = useState(null);
@ -35,24 +38,36 @@ export default function TaskShow() {
const setErrorMessage = (useContext as any)(ErrorContext)[1];
useEffect(() => {
const processResult = (result: any) => {
setTask(result);
HttpService.makeCallToBackend({
path: `/process-instances/${modifyProcessIdentifierForPathParam(
result.process_model_identifier
)}/${params.process_instance_id}/tasks`,
successCallback: setUserTasks,
});
};
const { targetUris } = useUriListForPermissions();
const permissionRequestData: PermissionsToCheck = {
[targetUris.processInstanceTaskListPath]: ['GET'],
};
const { ability, permissionsLoaded } = usePermissionFetcher(
permissionRequestData
);
HttpService.makeCallToBackend({
path: `/tasks/${params.process_instance_id}/${params.task_id}`,
successCallback: processResult,
// This causes the page to continuously reload
// failureCallback: setErrorMessage,
});
}, [params]);
useEffect(() => {
if (permissionsLoaded) {
const processResult = (result: any) => {
setTask(result);
if (ability.can('GET', targetUris.processInstanceTaskListPath)) {
HttpService.makeCallToBackend({
path: `/task-data/${modifyProcessIdentifierForPathParam(
result.process_model_identifier
)}/${params.process_instance_id}`,
successCallback: setUserTasks,
});
}
};
HttpService.makeCallToBackend({
path: `/tasks/${params.process_instance_id}/${params.task_id}`,
successCallback: processResult,
// This causes the page to continuously reload
// failureCallback: setErrorMessage,
});
}
}, [params, permissionsLoaded, ability, targetUris]);
const processSubmitResult = (result: any) => {
setErrorMessage(null);
@ -116,17 +131,18 @@ export default function TaskShow() {
}
return null;
});
return (
<Tabs
title="Steps in this process instance involving people"
selectedIndex={selectedTabIndex}
>
<TabList aria-label="List of tabs" contained>
{userTasksElement}
</TabList>
</Tabs>
);
}
return (
<Tabs
title="Steps in this process instance involving people"
selectedIndex={selectedTabIndex}
>
<TabList aria-label="List of tabs" contained>
{userTasksElement}
</TabList>
</Tabs>
);
return null;
};
const formElement = (taskToUse: any) => {
@ -207,7 +223,7 @@ export default function TaskShow() {
);
};
if (task && userTasks) {
if (task) {
const taskToUse = task as any;
let statusString = '';
if (taskToUse.state !== 'READY') {