reports seem to be working again w/ burnettk

This commit is contained in:
jasquat 2023-04-27 15:19:02 -04:00
parent e49734b9ef
commit b86ddf8a96
13 changed files with 401 additions and 399 deletions

View File

@ -0,0 +1,34 @@
"""empty message
Revision ID: 68adb1d504e1
Revises: 0c7428378d6e
Create Date: 2023-04-27 12:24:01.771698
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '68adb1d504e1'
down_revision = '0c7428378d6e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('process_instance_report', schema=None) as batch_op:
batch_op.add_column(sa.Column('json_data_hash', sa.String(length=255), nullable=False))
batch_op.create_index(batch_op.f('ix_process_instance_report_json_data_hash'), ['json_data_hash'], unique=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('process_instance_report', schema=None) as batch_op:
batch_op.drop_index(batch_op.f('ix_process_instance_report_json_data_hash'))
batch_op.drop_column('json_data_hash')
# ### end Alembic commands ###

View File

@ -1298,17 +1298,29 @@ paths:
items:
$ref: "#/components/schemas/Workflow"
/process-instances/report-metadata/{report_hash}:
/process-instances/report-metadata:
parameters:
- name: report_hash
in: path
required: true
description: The unique id of an existing report
in: query
required: false
description: The hash of a query that has been searched before.
schema:
type: string
- name: report_id
in: query
required: false
description: The unique id of an existing report.
schema:
type: integer
- name: report_identifier
in: query
required: false
description: Specifies the identifier of a report to use, if any
schema:
type: string
get:
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_report_metadata_show
summary: Returns the metadata associated with a given report hash.
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_report_show
summary: Returns the metadata associated with a given report key. This favors report_hash over report_id and report_identifier.
tags:
- Process Instances
responses:
@ -1341,20 +1353,20 @@ paths:
description: The page number to return. Defaults to page 1.
schema:
type: integer
get:
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_report_show
summary: Returns a report of process instances for a given process model
tags:
- Process Instances
responses:
"200":
description: Workflow.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Workflow"
# get:
# operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_report_show
# summary: Returns a report of process instances for a given process model
# tags:
# - Process Instances
# responses:
# "200":
# description: Workflow.
# content:
# application/json:
# schema:
# type: array
# items:
# $ref: "#/components/schemas/Workflow"
put:
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_report_update
summary: Updates a process instance report

View File

@ -1,4 +1,10 @@
from __future__ import annotations
import json
from hashlib import sha256
from flask import current_app
from typing import TypedDict
from sqlalchemy.dialects.mysql import insert as mysql_insert
from sqlalchemy.dialects.postgresql import insert as postgres_insert
from spiffworkflow_backend.models.db import db
from spiffworkflow_backend.models.db import SpiffworkflowBaseDBModel
@ -8,6 +14,11 @@ class JsonDataModelNotFoundError(Exception):
pass
class JsonDataDict(TypedDict):
hash: str
data: dict
# delta algorithm <- just to save it for when we want to try to implement it:
# a = {"hey": { "hey2": 2, "hey3": 3, "hey6": 7 }, "hey30": 3, "hey40": 4}
# b = {"hey": { "hey2": 4, "hey5": 3 }, "hey20": 2, "hey30": 3}
@ -42,3 +53,29 @@ class JsonDataModel(SpiffworkflowBaseDBModel):
@classmethod
def find_data_dict_by_hash(cls, hash: str) -> dict:
return cls.find_object_by_hash(hash).data
@classmethod
def insert_or_update_json_data_records(
cls, json_data_hash_to_json_data_dict_mapping: dict[str, JsonDataDict]
) -> None:
list_of_dicts = [*json_data_hash_to_json_data_dict_mapping.values()]
if len(list_of_dicts) > 0:
on_duplicate_key_stmt = None
if current_app.config["SPIFFWORKFLOW_BACKEND_DATABASE_TYPE"] == "mysql":
insert_stmt = mysql_insert(JsonDataModel).values(list_of_dicts)
on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(data=insert_stmt.inserted.data)
else:
insert_stmt = postgres_insert(JsonDataModel).values(list_of_dicts)
on_duplicate_key_stmt = insert_stmt.on_conflict_do_nothing(index_elements=["hash"])
db.session.execute(on_duplicate_key_stmt)
@classmethod
def insert_or_update_json_data_dict(cls, json_data_dict: JsonDataDict) -> None:
cls.insert_or_update_json_data_records({json_data_dict["hash"]: json_data_dict})
@classmethod
def create_and_insert_json_data_from_dict(cls, data: dict) -> str:
json_data_hash = sha256(json.dumps(data, sort_keys=True).encode("utf8")).hexdigest()
cls.insert_or_update_json_data_dict({'hash': json_data_hash, 'data': data})
db.session.commit()
return json_data_hash

View File

@ -1,5 +1,6 @@
"""Process_instance."""
from __future__ import annotations
from spiffworkflow_backend.models.json_data import JsonDataModel # noqa: F401
from dataclasses import dataclass
from typing import Any
@ -88,6 +89,11 @@ class ProcessInstanceReportModel(SpiffworkflowBaseDBModel):
created_at_in_seconds = db.Column(db.Integer)
updated_at_in_seconds = db.Column(db.Integer)
json_data_hash: str = db.Column(db.String(255), nullable=False, index=True)
def get_report_metadata(self) -> dict:
return JsonDataModel.find_data_dict_by_hash(self.json_data_hash)
@classmethod
def default_order_by(cls) -> list[str]:
"""Default_order_by."""
@ -154,10 +160,13 @@ class ProcessInstanceReportModel(SpiffworkflowBaseDBModel):
f"Process instance report with identifier already exists: {identifier}"
)
json_data_hash = JsonDataModel.create_and_insert_json_data_from_dict(report_metadata)
process_instance_report = cls(
identifier=identifier,
created_by_id=user.id,
report_metadata=report_metadata,
json_data_hash=json_data_hash,
)
db.session.add(process_instance_report)
db.session.commit()

View File

@ -335,25 +335,42 @@ def process_instance_list(
user=g.user,
)
json_data_hash = sha256(json.dumps(body['report_metadata'], sort_keys=True).encode("utf8")).hexdigest()
TaskService.insert_or_update_json_data_dict({'hash': json_data_hash, 'data': body['report_metadata']})
db.session.commit()
# json_data = JsonDataModel.query.filter_by(json_data_hash)
json_data_hash = JsonDataModel.create_and_insert_json_data_from_dict(body['report_metadata'])
response_json['report_hash'] = json_data_hash
db.session.commit()
return make_response(jsonify(response_json), 200)
def process_instance_report_metadata_show(
report_hash: str,
def process_instance_report_show(
report_hash: Optional[str] = None,
report_id: Optional[int] = None,
report_identifier: Optional[str] = None,
) -> flask.wrappers.Response:
json_data = JsonDataModel.query.filter_by(hash=report_hash).first()
if json_data is None:
if report_hash is None and report_id is None and report_identifier is None:
raise ApiError(
error_code="report_metadata_not_found",
message=f"Could not find report metadata for {report_hash}.",
error_code="report_key_missing",
message="A report key is needed to lookup a report. Either choose a report_hash, report_id, or report_identifier.",
)
return make_response(jsonify(json_data.data), 200)
response_result = {}
if report_hash is not None:
json_data = JsonDataModel.query.filter_by(hash=report_hash).first()
if json_data is None:
raise ApiError(
error_code="report_metadata_not_found",
message=f"Could not find report metadata for {report_hash}.",
)
response_result = {
"id": 0,
"identifier": "custom",
"name": "custom",
"report_metadata": json_data.data,
}
else:
response_result = ProcessInstanceReportService.report_with_identifier(g.user, report_id, report_identifier)
return make_response(jsonify(response_result), 200)
def process_instance_report_column_list(
@ -490,39 +507,39 @@ def process_instance_report_delete(
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
def process_instance_report_show(
report_id: int,
page: int = 1,
per_page: int = 100,
) -> flask.wrappers.Response:
"""Process_instance_report_show."""
process_instances = ProcessInstanceModel.query.order_by(
ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore
).paginate(page=page, per_page=per_page, error_out=False)
process_instance_report = ProcessInstanceReportModel.query.filter_by(
id=report_id,
created_by_id=g.user.id,
).first()
if process_instance_report is None:
raise ApiError(
error_code="unknown_process_instance_report",
message="Unknown process instance report",
status_code=404,
)
substitution_variables = request.args.to_dict()
result_dict = process_instance_report.generate_report(process_instances.items, substitution_variables)
# update this if we go back to a database query instead of filtering in memory
result_dict["pagination"] = {
"count": len(result_dict["results"]),
"total": len(result_dict["results"]),
"pages": 1,
}
return Response(json.dumps(result_dict), status=200, mimetype="application/json")
# def process_instance_report_show(
# report_id: int,
# page: int = 1,
# per_page: int = 100,
# ) -> flask.wrappers.Response:
# """Process_instance_report_show."""
# process_instances = ProcessInstanceModel.query.order_by(
# ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore
# ).paginate(page=page, per_page=per_page, error_out=False)
#
# process_instance_report = ProcessInstanceReportModel.query.filter_by(
# id=report_id,
# created_by_id=g.user.id,
# ).first()
# if process_instance_report is None:
# raise ApiError(
# error_code="unknown_process_instance_report",
# message="Unknown process instance report",
# status_code=404,
# )
#
# substitution_variables = request.args.to_dict()
# result_dict = process_instance_report.generate_report(process_instances.items, substitution_variables)
#
# # update this if we go back to a database query instead of filtering in memory
# result_dict["pagination"] = {
# "count": len(result_dict["results"]),
# "total": len(result_dict["results"]),
# "pages": 1,
# }
#
# return Response(json.dumps(result_dict), status=200, mimetype="application/json")
#
def process_instance_task_list_without_task_data_for_me(
modified_process_model_identifier: str,

View File

@ -1,5 +1,6 @@
"""APIs for dealing with process groups, process models, and process instances."""
import json
from spiffworkflow_backend.models.json_data import JsonDataModel # noqa: F401
import os
import uuid
from sys import exc_info
@ -220,7 +221,7 @@ def task_data_update(
task_model, new_task_data_dict, "json_data_hash"
)
if json_data_dict is not None:
TaskService.insert_or_update_json_data_records({json_data_dict["hash"]: json_data_dict})
JsonDataModel.insert_or_update_json_data_records({json_data_dict["hash"]: json_data_dict})
ProcessInstanceTmpService.add_event_to_process_instance(
process_instance, ProcessInstanceEventType.task_data_edited.value, task_guid=task_guid
)
@ -537,7 +538,7 @@ def _task_submit_shared(
task_model, spiff_task.data, "json_data_hash"
)
if json_data_dict is not None:
TaskService.insert_or_update_json_data_dict(json_data_dict)
JsonDataModel.insert_or_update_json_data_dict(json_data_dict)
db.session.add(task_model)
db.session.commit()
else:

View File

@ -1737,7 +1737,7 @@ class ProcessInstanceProcessor:
bpmn_definition_to_task_definitions_mappings=self.bpmn_definition_to_task_definitions_mappings,
)
task_service.update_task_model(task_model, spiff_task)
TaskService.insert_or_update_json_data_records(task_service.json_data_dicts)
JsonDataModel.insert_or_update_json_data_records(task_service.json_data_dicts)
ProcessInstanceTmpService.add_event_to_process_instance(
self.process_instance_model,

View File

@ -15,14 +15,12 @@ from SpiffWorkflow.exceptions import WorkflowException # type: ignore
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
from SpiffWorkflow.task import TaskState
from SpiffWorkflow.task import TaskStateNames
from sqlalchemy.dialects.mysql import insert as mysql_insert
from sqlalchemy.dialects.postgresql import insert as postgres_insert
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
from spiffworkflow_backend.models.bpmn_process import BpmnProcessNotFoundError
from spiffworkflow_backend.models.bpmn_process_definition import BpmnProcessDefinitionModel
from spiffworkflow_backend.models.db import db
from spiffworkflow_backend.models.json_data import JsonDataModel # noqa: F401
from spiffworkflow_backend.models.json_data import JsonDataDict, JsonDataModel # noqa: F401
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
from spiffworkflow_backend.models.process_instance_event import ProcessInstanceEventModel
from spiffworkflow_backend.models.process_instance_event import ProcessInstanceEventType
@ -38,11 +36,6 @@ class StartAndEndTimes(TypedDict):
end_in_seconds: Optional[float]
class JsonDataDict(TypedDict):
hash: str
data: dict
class TaskModelError(Exception):
"""Copied from SpiffWorkflow.exceptions.WorkflowTaskException.
@ -130,7 +123,7 @@ class TaskService:
db.session.bulk_save_objects(self.bpmn_processes.values())
db.session.bulk_save_objects(self.task_models.values())
db.session.bulk_save_objects(self.process_instance_events.values())
self.__class__.insert_or_update_json_data_records(self.json_data_dicts)
JsonDataModel.insert_or_update_json_data_records(self.json_data_dicts)
def process_parents_and_children_and_save_to_database(
self,
@ -483,10 +476,6 @@ class TaskService:
bpmn_process.json_data_hash = bpmn_process_data_hash
return json_data_dict
@classmethod
def insert_or_update_json_data_dict(cls, json_data_dict: JsonDataDict) -> None:
TaskService.insert_or_update_json_data_records({json_data_dict["hash"]: json_data_dict})
@classmethod
def update_task_data_on_task_model_and_return_dict_if_updated(
cls, task_model: TaskModel, task_data_dict: dict, task_model_data_column: str
@ -610,21 +599,6 @@ class TaskService:
new_properties_json["state"] = getattr(TaskState, state)
task_model.properties_json = new_properties_json
@classmethod
def insert_or_update_json_data_records(
cls, json_data_hash_to_json_data_dict_mapping: dict[str, JsonDataDict]
) -> None:
list_of_dicts = [*json_data_hash_to_json_data_dict_mapping.values()]
if len(list_of_dicts) > 0:
on_duplicate_key_stmt = None
if current_app.config["SPIFFWORKFLOW_BACKEND_DATABASE_TYPE"] == "mysql":
insert_stmt = mysql_insert(JsonDataModel).values(list_of_dicts)
on_duplicate_key_stmt = insert_stmt.on_duplicate_key_update(data=insert_stmt.inserted.data)
else:
insert_stmt = postgres_insert(JsonDataModel).values(list_of_dicts)
on_duplicate_key_stmt = insert_stmt.on_conflict_do_nothing(index_elements=["hash"])
db.session.execute(on_duplicate_key_stmt)
@classmethod
def get_extensions_from_task_model(cls, task_model: TaskModel) -> dict:
task_definition = task_model.task_definition

View File

@ -75,73 +75,73 @@ export default function ProcessInstanceListSaveAsReport({
const addProcessInstanceReport = (event: any) => {
event.preventDefault();
// TODO: make a field to set this
let orderByArray = ['-start_in_seconds', '-id'];
if (orderBy) {
orderByArray = orderBy.split(',').filter((n) => n);
}
const filterByArray: any = [];
if (processModelSelection) {
filterByArray.push({
field_name: 'process_model_identifier',
field_value: processModelSelection.id,
});
}
if (processInitiatorSelection) {
filterByArray.push({
field_name: 'process_initiator_username',
field_value: processInitiatorSelection.username,
});
}
if (processStatusSelection.length > 0) {
filterByArray.push({
field_name: 'process_status',
field_value: processStatusSelection.join(','),
operator: 'in',
});
}
if (startFromSeconds) {
filterByArray.push({
field_name: 'start_from',
field_value: startFromSeconds,
});
}
if (startToSeconds) {
filterByArray.push({
field_name: 'start_to',
field_value: startToSeconds,
});
}
if (endFromSeconds) {
filterByArray.push({
field_name: 'end_from',
field_value: endFromSeconds,
});
}
if (endToSeconds) {
filterByArray.push({
field_name: 'end_to',
field_value: endToSeconds,
});
}
reportMetadata.filter_by.forEach((reportFilter: ReportFilter) => {
columnArray.forEach((reportColumn: ReportColumn) => {
if (
reportColumn.accessor === reportFilter.field_name &&
reportColumn.filterable
) {
filterByArray.push(reportFilter);
}
});
});
// // TODO: make a field to set this
// let orderByArray = ['-start_in_seconds', '-id'];
// if (orderBy) {
// orderByArray = orderBy.split(',').filter((n) => n);
// }
// const filterByArray: any = [];
//
// if (processModelSelection) {
// filterByArray.push({
// field_name: 'process_model_identifier',
// field_value: processModelSelection.id,
// });
// }
//
// if (processInitiatorSelection) {
// filterByArray.push({
// field_name: 'process_initiator_username',
// field_value: processInitiatorSelection.username,
// });
// }
//
// if (processStatusSelection.length > 0) {
// filterByArray.push({
// field_name: 'process_status',
// field_value: processStatusSelection.join(','),
// operator: 'in',
// });
// }
//
// if (startFromSeconds) {
// filterByArray.push({
// field_name: 'start_from',
// field_value: startFromSeconds,
// });
// }
//
// if (startToSeconds) {
// filterByArray.push({
// field_name: 'start_to',
// field_value: startToSeconds,
// });
// }
//
// if (endFromSeconds) {
// filterByArray.push({
// field_name: 'end_from',
// field_value: endFromSeconds,
// });
// }
//
// if (endToSeconds) {
// filterByArray.push({
// field_name: 'end_to',
// field_value: endToSeconds,
// });
// }
//
// reportMetadata.filter_by.forEach((reportFilter: ReportFilter) => {
// columnArray.forEach((reportColumn: ReportColumn) => {
// if (
// reportColumn.accessor === reportFilter.field_name &&
// reportColumn.filterable
// ) {
// filterByArray.push(reportFilter);
// }
// });
// });
let path = `/process-instances/reports`;
let httpMethod = 'POST';
@ -156,11 +156,7 @@ export default function ProcessInstanceListSaveAsReport({
httpMethod,
postBody: {
identifier,
report_metadata: {
columns: columnArray,
order_by: orderByArray,
filter_by: filterByArray,
},
report_metadata: reportMetadata,
},
});
handleSaveFormClose();

View File

@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
// @ts-ignore
@ -37,10 +37,7 @@ import {
convertSecondsToFormattedDateString,
convertSecondsToFormattedDateTime,
convertSecondsToFormattedTimeHoursMinutes,
decodeBase64,
encodeBase64,
getPageInfoFromSearchParams,
getProcessModelFullIdentifierFromSearchParams,
modifyProcessIdentifierForPathParam,
refreshAtInterval,
REFRESH_INTERVAL_SECONDS,
@ -119,6 +116,7 @@ export default function ProcessInstanceListTable({
if (variant === 'all') {
processInstanceApiSearchPath = '/process-instances';
}
const params = useParams();
const [searchParams, setSearchParams] = useSearchParams();
const navigate = useNavigate();
@ -282,9 +280,11 @@ export default function ProcessInstanceListTable({
setProcessInstanceFilters(result.filters);
setReportMetadata(result.report.report_metadata);
if (result.report.id) {
setProcessInstanceReportSelection(result.report);
}
// if (processInstanceReport) {
// if (processInstanceReport.id > 0) {
// setProcessInstanceReportSelection(processInstanceReport);
// }
// }
if (result.report_hash) {
searchParams.set('report_hash', result.report_hash);
setSearchParams(searchParams);
@ -301,6 +301,11 @@ export default function ProcessInstanceListTable({
}
};
const getData = useCallback(() => {
console.log('WE DO STUFF');
stopRefreshing(null);
}, []);
// eslint-disable-next-line sonarjs/cognitive-complexity
useEffect(() => {
if (!permissionsLoaded) {
@ -318,9 +323,6 @@ export default function ProcessInstanceListTable({
setPagination(result.pagination);
setProcessInstanceFilters(result.filters);
setReportMetadata(result.report.report_metadata);
if (result.report.id) {
setProcessInstanceReportSelection(result.report);
}
}
// Useful to stop refreshing if an api call gets an error
@ -334,18 +336,21 @@ export default function ProcessInstanceListTable({
}
};
function getProcessInstances(
reportMetadataBody: ReportMetadata | null = null
processInstanceReport: ProcessInstanceReport | null = null
) {
if (listHasBeenFiltered) {
return;
}
let reportMetadataBodyToUse = reportMetadataBody;
if (!reportMetadataBodyToUse) {
reportMetadataBodyToUse = {
columns: [],
filter_by: [],
order_by: [],
};
let reportMetadataBodyToUse: ReportMetadata = {
columns: [],
filter_by: [],
order_by: [],
};
if (processInstanceReport) {
reportMetadataBodyToUse = processInstanceReport.report_metadata;
if (processInstanceReport.id > 0) {
setProcessInstanceReportSelection(processInstanceReport);
}
}
let selectedProcessModelIdentifier = processModelFullIdentifier;
@ -391,22 +396,6 @@ export default function ProcessInstanceListTable({
}
);
// if (searchParams.get('report_id')) {
// queryParamString += `&report_id=${searchParams.get('report_id')}`;
// } else if (reportIdentifier) {
// queryParamString += `&report_identifier=${reportIdentifier}`;
// }
// if (searchParams.get('report_columns')) {
// const reportColumnsBase64 = searchParams.get('report_columns');
// if (reportColumnsBase64) {
// const reportColumnsList = JSON.parse(
// decodeBase64(reportColumnsBase64)
// );
// postBody.columns = reportColumnsList;
// }
// }
// eslint-disable-next-line prefer-const
let { page, perPage } = getPageInfoFromSearchParams(
searchParams,
@ -427,8 +416,8 @@ export default function ProcessInstanceListTable({
path: `${processInstanceApiSearchPath}?${queryParamString}`,
successCallback: setProcessInstancesFromResult,
httpMethod: 'POST',
failureCallback: stopRefreshing,
onUnauthorized: stopRefreshing,
failureCallback: getData,
onUnauthorized: getData,
postBody: {
report_metadata: reportMetadataBodyToUse,
},
@ -438,10 +427,19 @@ export default function ProcessInstanceListTable({
if (listHasBeenFiltered) {
return;
}
const reportHash = searchParams.get('report_hash');
if (reportHash) {
const queryParams: string[] = [];
['report_hash', 'report_id', 'report_identifier'].forEach(
(paramName: string) => {
if (searchParams.get(paramName)) {
queryParams.push(`${paramName}=${searchParams.get(paramName)}`);
}
}
);
if (queryParams.length > 0) {
const queryParamString = `?${queryParams.join('&')}`;
HttpService.makeCallToBackend({
path: `/process-instances/report-metadata/${reportHash}`,
path: `/process-instances/report-metadata${queryParamString}`,
successCallback: getProcessInstances,
});
} else {
@ -697,6 +695,85 @@ export default function ProcessInstanceListTable({
}
};
const getNewReportMetadataBasedOnPageWidgets = () => {
const {
valid,
startFromSeconds,
startToSeconds,
endFromSeconds,
endToSeconds,
} = calculateStartAndEndSeconds();
if (!valid) {
return null;
}
let newReportMetadata = null;
if (reportMetadata) {
newReportMetadata = { ...reportMetadata };
}
if (!newReportMetadata) {
newReportMetadata = {
columns: [],
filter_by: [],
order_by: [],
};
}
addFieldValueToReportMetadata(
newReportMetadata,
'start_from',
startFromSeconds
);
addFieldValueToReportMetadata(
newReportMetadata,
'start_to',
startToSeconds
);
addFieldValueToReportMetadata(
newReportMetadata,
'end_from',
endFromSeconds
);
addFieldValueToReportMetadata(newReportMetadata, 'end_to', endToSeconds);
if (processStatusSelection.length > 0) {
addFieldValueToReportMetadata(
newReportMetadata,
'process_status',
processStatusSelection.join(',')
);
} else {
removeFieldFromReportMetadata(newReportMetadata, 'process_status');
}
if (processModelSelection) {
addFieldValueToReportMetadata(
newReportMetadata,
'process_model_identifier',
processModelSelection.id
);
} else {
removeFieldFromReportMetadata(
newReportMetadata,
'process_model_identifier'
);
}
if (processInitiatorSelection) {
addFieldValueToReportMetadata(
newReportMetadata,
'process_initiator_username',
processInitiatorSelection.username
);
} else {
removeFieldFromReportMetadata(
newReportMetadata,
'process_initiator_username'
);
}
return newReportMetadata;
};
const applyFilter = (event: any) => {
event.preventDefault();
setProcessInitiatorNotFoundErrorText('');
@ -707,74 +784,10 @@ export default function ProcessInstanceListTable({
undefined,
paginationQueryParamPrefix
);
const {
valid,
startFromSeconds,
startToSeconds,
endFromSeconds,
endToSeconds,
} = calculateStartAndEndSeconds();
if (!valid) {
return;
}
let postBody = null;
if (reportMetadata) {
postBody = { ...reportMetadata };
}
if (!postBody) {
postBody = {
columns: [],
filter_by: [],
order_by: [],
};
}
addFieldValueToReportMetadata(postBody, 'start_from', startFromSeconds);
addFieldValueToReportMetadata(postBody, 'start_to', startToSeconds);
addFieldValueToReportMetadata(postBody, 'end_from', endFromSeconds);
addFieldValueToReportMetadata(postBody, 'end_to', endToSeconds);
if (processStatusSelection.length > 0) {
addFieldValueToReportMetadata(
postBody,
'process_status',
processStatusSelection.join(',')
);
} else {
removeFieldFromReportMetadata(postBody, 'process_status');
}
if (processModelSelection) {
addFieldValueToReportMetadata(
postBody,
'process_model_identifier',
processModelSelection.id
);
} else {
removeFieldFromReportMetadata(postBody, 'process_model_identifier');
}
// if (processInstanceReportSelection) {
// addFieldValueToReportMetadata(
// postBody,
// 'report_id',
// processInstanceReportSelection.id.toString()
// );
// }
if (processInitiatorSelection) {
addFieldValueToReportMetadata(
postBody,
'process_initiator_username',
processInitiatorSelection.username
);
} else {
removeFieldFromReportMetadata(postBody, 'process_initiator_username');
}
const newReportMetadata = getNewReportMetadataBasedOnPageWidgets();
setListHasBeenFiltered(true);
setReportMetadata(postBody);
setReportMetadata(newReportMetadata);
searchParams.set('per_page', perPage.toString());
searchParams.set('page', page.toString());
setSearchParams(searchParams);
@ -783,7 +796,7 @@ export default function ProcessInstanceListTable({
HttpService.makeCallToBackend({
path: `${processInstanceApiSearchPath}?${queryParamString}`,
httpMethod: 'POST',
postBody: { report_metadata: postBody },
postBody: { report_metadata: newReportMetadata },
failureCallback: stopRefreshing,
onUnauthorized: stopRefreshing,
successCallback: (result: any) => {
@ -907,14 +920,12 @@ export default function ProcessInstanceListTable({
});
};
// TODO onSuccess reload/select the new report in the report search
const onSaveReportSuccess = (result: any, mode: string) => {
processInstanceReportDidChange(
{
selectedItem: result,
},
mode
);
const onSaveReportSuccess = (
processInstanceReport: ProcessInstanceReport
) => {
setProcessInstanceReportSelection(processInstanceReport);
searchParams.set('report_id', processInstanceReport.id.toString());
setSearchParams(searchParams);
};
const saveAsReportComponent = () => {
@ -926,7 +937,9 @@ export default function ProcessInstanceListTable({
endToSeconds,
} = calculateStartAndEndSeconds(false);
if (!valid || !reportMetadata) {
const newReportMetadata = getNewReportMetadataBasedOnPageWidgets();
if (!valid || !reportMetadata || !newReportMetadata) {
return null;
}
return (
@ -940,7 +953,7 @@ export default function ProcessInstanceListTable({
processInitiatorSelection={processInitiatorSelection}
processStatusSelection={processStatusSelection}
processInstanceReportSelection={processInstanceReportSelection}
reportMetadata={reportMetadata}
reportMetadata={newReportMetadata}
startFromSeconds={startFromSeconds}
startToSeconds={startToSeconds}
endFromSeconds={endFromSeconds}
@ -1052,15 +1065,15 @@ export default function ProcessInstanceListTable({
{ filter_field_value: '', filter_operator: '' }
);
if (reportColumn.filterable) {
const reportFilter = getFilterByFromReportMetadata(
reportColumnForEditing.accessor
);
if (reportFilter) {
reportColumnForEditing.filter_field_value =
reportFilter.field_value || '';
reportColumnForEditing.filter_operator =
reportFilter.operator || 'equals';
}
const reportFilter = getFilterByFromReportMetadata(
reportColumnForEditing.accessor
);
if (reportFilter) {
reportColumnForEditing.filter_field_value =
reportFilter.field_value || '';
reportColumnForEditing.filter_operator =
reportFilter.operator || 'equals';
}
}
return reportColumnForEditing;
};
@ -1622,6 +1635,8 @@ export default function ProcessInstanceListTable({
<ProcessInstanceReportSearch
onChange={processInstanceReportDidChange}
selectedItem={processInstanceReportSelection}
selectedReportId={searchParams.get('report_id')}
handleSetSelectedReportCallback={setProcessInstanceReportSelection}
/>
</Column>,
];

View File

@ -5,7 +5,6 @@ import {
FormLabel,
// @ts-ignore
} from '@carbon/react';
import { useSearchParams } from 'react-router-dom';
import { truncateString } from '../helpers';
import { ProcessInstanceReport } from '../interfaces';
import HttpService from '../services/HttpService';
@ -14,32 +13,42 @@ type OwnProps = {
onChange: (..._args: any[]) => any;
selectedItem?: ProcessInstanceReport | null;
titleText?: string;
selectedReportId?: string | null;
handleSetSelectedReportCallback?: Function;
};
export default function ProcessInstanceReportSearch({
selectedItem,
onChange,
selectedReportId,
handleSetSelectedReportCallback,
titleText = 'Process instance perspectives',
}: OwnProps) {
const [processInstanceReports, setProcessInstanceReports] = useState<
ProcessInstanceReport[] | null
>(null);
const [searchParams] = useSearchParams();
const reportId = searchParams.get('report_id');
useEffect(() => {
const selectedReportIdAsNumber = Number(selectedReportId);
function setProcessInstanceReportsFromResult(
result: ProcessInstanceReport[]
) {
setProcessInstanceReports(result);
if (selectedReportId && handleSetSelectedReportCallback) {
result.forEach((processInstanceReport: ProcessInstanceReport) => {
if (processInstanceReport.id === selectedReportIdAsNumber) {
handleSetSelectedReportCallback(processInstanceReport);
}
});
}
}
HttpService.makeCallToBackend({
path: `/process-instances/reports`,
successCallback: setProcessInstanceReportsFromResult,
});
}, [reportId]);
}, [handleSetSelectedReportCallback, selectedReportId]);
const reportSelectionString = (
processInstanceReport: ProcessInstanceReport

View File

@ -8,7 +8,6 @@ import ProcessGroupEdit from './ProcessGroupEdit';
import ProcessModelShow from './ProcessModelShow';
import ProcessModelEditDiagram from './ProcessModelEditDiagram';
import ProcessInstanceList from './ProcessInstanceList';
import ProcessInstanceReportShow from './ProcessInstanceReportShow';
import ProcessModelNew from './ProcessModelNew';
import ProcessModelEdit from './ProcessModelEdit';
import ProcessInstanceShow from './ProcessInstanceShow';
@ -88,10 +87,6 @@ export default function AdminRoutes() {
path="process-instances/reports"
element={<ProcessInstanceReportList />}
/>
<Route
path="process-instances/reports/:report_identifier"
element={<ProcessInstanceReportShow />}
/>
<Route
path="process-instances/reports/new"
element={<ProcessInstanceReportNew />}

View File

@ -1,97 +0,0 @@
import { useEffect, useState } from 'react';
import { useParams, useSearchParams } from 'react-router-dom';
// @ts-ignore
import { Button, Table } from '@carbon/react';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import PaginationForTable from '../components/PaginationForTable';
import HttpService from '../services/HttpService';
import { getPageInfoFromSearchParams } from '../helpers';
const PER_PAGE_FOR_PROCESS_INSTANCE_REPORT = 500;
export default function ProcessInstanceReport() {
const params = useParams();
const [searchParams] = useSearchParams();
const [processInstances, setProcessInstances] = useState([]);
const [reportMetadata, setReportMetadata] = useState({});
const [pagination, setPagination] = useState(null);
useEffect(() => {
const processResult = (result: any) => {
const processInstancesFromApi = result.results;
setProcessInstances(processInstancesFromApi);
setReportMetadata(result.report_metadata);
setPagination(result.pagination);
};
function getProcessInstances() {
const { page, perPage } = getPageInfoFromSearchParams(
searchParams,
PER_PAGE_FOR_PROCESS_INSTANCE_REPORT
);
let query = `?page=${page}&per_page=${perPage}`;
searchParams.forEach((value, key) => {
if (key !== 'page' && key !== 'per_page') {
query += `&${key}=${value}`;
}
});
HttpService.makeCallToBackend({
path: `/process-instances/reports/${params.report_identifier}${query}`,
successCallback: processResult,
});
}
getProcessInstances();
}, [searchParams, params]);
const buildTable = () => {
const headers = (reportMetadata as any).columns.map((column: any) => {
return <th>{(column as any).Header}</th>;
});
const rows = processInstances.map((row) => {
const currentRow = (reportMetadata as any).columns.map((column: any) => {
return <td>{(row as any)[column.accessor]}</td>;
});
return <tr key={(row as any).id}>{currentRow}</tr>;
});
return (
<Table striped bordered>
<thead>
<tr>{headers}</tr>
</thead>
<tbody>{rows}</tbody>
</Table>
);
};
if (pagination) {
const { page, perPage } = getPageInfoFromSearchParams(
searchParams,
PER_PAGE_FOR_PROCESS_INSTANCE_REPORT
);
return (
<main>
<ProcessBreadcrumb
hotCrumbs={[['Process Groups', '/admin'], ['Process Instance']]}
/>
<h1>Process Instance Perspective: {params.report_identifier}</h1>
<Button
href={`/admin/process-instances/reports/${params.report_identifier}/edit`}
>
Edit process instance perspective
</Button>
<PaginationForTable
page={page}
perPage={perPage}
pagination={pagination}
tableToDisplay={buildTable()}
/>
</main>
);
}
return null;
}