more filter work

This commit is contained in:
jasquat 2023-04-27 07:28:06 -04:00
parent 09fca807a4
commit 2376080267
4 changed files with 247 additions and 226 deletions

View File

@ -1298,6 +1298,29 @@ paths:
items: items:
$ref: "#/components/schemas/Workflow" $ref: "#/components/schemas/Workflow"
/process-instances/report-metadata/{report_hash}:
parameters:
- name: report_hash
in: path
required: true
description: The unique id of an existing report
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.
tags:
- Process Instances
responses:
"200":
description: Workflow.
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Workflow"
/process-instances/reports/{report_id}: /process-instances/reports/{report_id}:
parameters: parameters:
- name: report_id - name: report_id

View File

@ -1,5 +1,7 @@
"""APIs for dealing with process groups, process models, and process instances.""" """APIs for dealing with process groups, process models, and process instances."""
import base64 import base64
from hashlib import sha256
from spiffworkflow_backend.models.json_data import JsonDataModel # noqa: F401
import json import json
from typing import Any from typing import Any
from typing import Dict from typing import Dict
@ -333,9 +335,27 @@ def process_instance_list(
user=g.user, 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)
response_json['report_hash'] = json_data_hash
return make_response(jsonify(response_json), 200) return make_response(jsonify(response_json), 200)
def process_instance_report_metadata_show(
report_hash: str,
) -> flask.wrappers.Response:
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}.",
)
return make_response(jsonify(json_data.data), 200)
def process_instance_report_column_list( def process_instance_report_column_list(
process_model_identifier: Optional[str] = None, process_model_identifier: Optional[str] = None,
) -> flask.wrappers.Response: ) -> flask.wrappers.Response:

View File

@ -357,6 +357,7 @@ class TestProcessInstanceProcessor(BaseTest):
human_task_one = process_instance.active_human_tasks[0] human_task_one = process_instance.active_human_tasks[0]
spiff_manual_task = processor.bpmn_process_instance.get_task_from_id(UUID(human_task_one.task_id)) spiff_manual_task = processor.bpmn_process_instance.get_task_from_id(UUID(human_task_one.task_id))
ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one) ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one)
import pdb; pdb.set_trace()
assert ( assert (
len(process_instance.active_human_tasks) == 0 len(process_instance.active_human_tasks) == 0
), "expected 0 active human tasks after 2nd one is completed" ), "expected 0 active human tasks after 2nd one is completed"

View File

@ -155,6 +155,9 @@ export default function ProcessInstanceListTable({
const [requiresRefilter, setRequiresRefilter] = useState<boolean>(false); const [requiresRefilter, setRequiresRefilter] = useState<boolean>(false);
const [lastColumnFilter, setLastColumnFilter] = useState<string>(''); const [lastColumnFilter, setLastColumnFilter] = useState<string>('');
const [listHasBeenFiltered, setListHasBeenFiltered] =
useState<boolean>(false);
const preferredUsername = UserService.getPreferredUsername(); const preferredUsername = UserService.getPreferredUsername();
const userEmail = UserService.getUserEmail(); const userEmail = UserService.getUserEmail();
@ -280,8 +283,10 @@ export default function ProcessInstanceListTable({
if (result.report.id) { if (result.report.id) {
setProcessInstanceReportSelection(result.report); setProcessInstanceReportSelection(result.report);
} }
// searchParams.set('key', result.hash); if (result.report_hash) {
// setSearchParams(searchParams); searchParams.set('report_hash', result.report_hash);
setSearchParams(searchParams);
}
} }
const clearRefreshRef = useRef<any>(null); const clearRefreshRef = useRef<any>(null);
@ -296,6 +301,10 @@ export default function ProcessInstanceListTable({
// eslint-disable-next-line sonarjs/cognitive-complexity // eslint-disable-next-line sonarjs/cognitive-complexity
useEffect(() => { useEffect(() => {
// we apparently cannot use a state set in a useEffect from within that same useEffect
// so use a variable instead
let processModelSelectionItemsForUseEffect: ProcessModel[] = [];
function setProcessInstancesFromResult(result: any) { function setProcessInstancesFromResult(result: any) {
setRequiresRefilter(false); setRequiresRefilter(false);
const processInstancesFromApi = result.results; const processInstancesFromApi = result.results;
@ -307,8 +316,6 @@ export default function ProcessInstanceListTable({
if (result.report.id) { if (result.report.id) {
setProcessInstanceReportSelection(result.report); setProcessInstanceReportSelection(result.report);
} }
// searchParams.set('key', result.hash);
// setSearchParams(searchParams);
} }
// Useful to stop refreshing if an api call gets an error // Useful to stop refreshing if an api call gets an error
@ -321,7 +328,115 @@ export default function ProcessInstanceListTable({
console.error(error); console.error(error);
} }
}; };
function getProcessInstances() { function getProcessInstances(
reportMetadataBody: ReportMetadata | null = null
) {
if (listHasBeenFiltered) {
return;
}
let reportMetadataBodyToUse = reportMetadataBody;
if (!reportMetadataBodyToUse) {
reportMetadataBodyToUse = {
columns: [],
filter_by: [],
order_by: [],
};
}
let selectedProcessModelIdentifier = processModelFullIdentifier;
reportMetadataBodyToUse.filter_by.forEach(
(reportFilter: ReportFilter) => {
if (reportFilter.field_name === 'process_status') {
setProcessStatusSelection(
(reportFilter.field_value || '').split(',')
);
} else if (reportFilter.field_name === 'process_model_identifier') {
selectedProcessModelIdentifier =
reportFilter.field_value || undefined;
} else if (dateParametersToAlwaysFilterBy[reportFilter.field_name]) {
const dateFunctionToCall =
dateParametersToAlwaysFilterBy[reportFilter.field_name][0];
const timeFunctionToCall =
dateParametersToAlwaysFilterBy[reportFilter.field_name][1];
if (reportFilter.field_value) {
const dateString = convertSecondsToFormattedDateString(
reportFilter.field_value as any
);
dateFunctionToCall(dateString);
const timeString = convertSecondsToFormattedTimeHoursMinutes(
reportFilter.field_value as any
);
timeFunctionToCall(timeString);
setShowFilterOptions(true);
}
}
}
);
processModelSelectionItemsForUseEffect.forEach(
(processModel: ProcessModel) => {
if (processModel.id === selectedProcessModelIdentifier) {
setProcessModelSelection(processModel);
}
}
);
// const postBody: ReportMetadata = {
// columns: [],
// filter_by: [],
// order_by: [],
// };
//
// 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;
// }
// }
// if (searchParams.get('report_filter_by')) {
// const reportFilterByBase64 = searchParams.get('report_filter_by');
// if (reportFilterByBase64) {
// const reportFilterByList = JSON.parse(
// decodeBase64(reportFilterByBase64)
// );
// postBody.filter_by = reportFilterByList;
// }
// }
//
// Object.keys(parametersToGetFromSearchParams).forEach(
// (paramName: string) => {
// if (
// paramName === 'process_model_identifier' &&
// processModelFullIdentifier
// ) {
// postBody.filter_by.push({
// field_name: 'process_model_identifier',
// field_value: processModelFullIdentifier,
// });
// } else if (searchParams.get(paramName)) {
// // @ts-expect-error TS(7053) FIXME:
// const functionToCall = parametersToGetFromSearchParams[paramName];
// postBody.filter_by.push({
// field_name: paramName,
// field_value: searchParams.get(paramName),
// });
// if (functionToCall !== null) {
// functionToCall(searchParams.get(paramName) || '');
// }
// setShowFilterOptions(true);
// }
// }
// );
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let { page, perPage } = getPageInfoFromSearchParams( let { page, perPage } = getPageInfoFromSearchParams(
searchParams, searchParams,
@ -334,172 +449,52 @@ export default function ProcessInstanceListTable({
perPage = perPageOptions[1]; perPage = perPageOptions[1];
} }
let queryParamString = `per_page=${perPage}&page=${page}`; let queryParamString = `per_page=${perPage}&page=${page}`;
// "columns": [
// {"Header": "id", "accessor": "id"},
// {
// "Header": "process_model_display_name",
// "accessor": "process_model_display_name",
// },
// {"Header": "start_in_seconds", "accessor": "start_in_seconds"},
// {"Header": "end_in_seconds", "accessor": "end_in_seconds"},
// {"Header": "status", "accessor": "status"},
// ],
// "filter_by": [
// {"field_name": "initiated_by_me", "field_value": "true"},
// {"field_name": "has_terminal_status", "field_value": "true"},
// ],
// "order_by": ["-start_in_seconds", "-id"],
const postBody: ReportMetadata = {
columns: [],
filter_by: [],
order_by: [],
};
// const userAppliedFilter = searchParams.get('user_filter');
// if (userAppliedFilter) {
// queryParamString += `&user_filter=${userAppliedFilter}`;
// }
if (searchParams.get('report_id')) {
queryParamString += `&report_id=${searchParams.get('report_id')}`;
} else if (reportIdentifier) {
queryParamString += `&report_identifier=${reportIdentifier}`;
}
if (searchParams.get('report_columns')) {
// queryParamString += `&report_columns=${searchParams.get(
// 'report_columns'
// )}`;
// const reportColumnsBase64 = encodeBase64(JSON.stringify(reportColumns()));
const reportColumnsBase64 = searchParams.get('report_columns');
if (reportColumnsBase64) {
const reportColumnsList = JSON.parse(
decodeBase64(reportColumnsBase64)
);
postBody.columns = reportColumnsList;
}
}
if (searchParams.get('report_filter_by')) {
// queryParamString += `&report_filter_by=${searchParams.get(
// 'report_filter_by'
// )}`;
const reportFilterByBase64 = searchParams.get('report_filter_by');
if (reportFilterByBase64) {
const reportFilterByList = JSON.parse(
decodeBase64(reportFilterByBase64)
);
postBody.filter_by = reportFilterByList;
}
}
Object.keys(dateParametersToAlwaysFilterBy).forEach(
(paramName: string) => {
const dateFunctionToCall =
dateParametersToAlwaysFilterBy[paramName][0];
const timeFunctionToCall =
dateParametersToAlwaysFilterBy[paramName][1];
const searchParamValue = searchParams.get(paramName);
if (searchParamValue) {
// queryParamString += `&${paramName}=${searchParamValue}`;
postBody.filter_by.push({
field_name: paramName,
field_value: searchParamValue,
});
const dateString = convertSecondsToFormattedDateString(
searchParamValue as any
);
dateFunctionToCall(dateString);
const timeString = convertSecondsToFormattedTimeHoursMinutes(
searchParamValue as any
);
timeFunctionToCall(timeString);
setShowFilterOptions(true);
}
}
);
Object.keys(parametersToGetFromSearchParams).forEach(
(paramName: string) => {
if (
paramName === 'process_model_identifier' &&
processModelFullIdentifier
) {
// queryParamString += `&process_model_identifier=${processModelFullIdentifier}`;
postBody.filter_by.push({
field_name: 'process_model_identifier',
field_value: processModelFullIdentifier,
});
} else if (searchParams.get(paramName)) {
// @ts-expect-error TS(7053) FIXME:
const functionToCall = parametersToGetFromSearchParams[paramName];
// queryParamString += `&${paramName}=${searchParams.get(paramName)}`;
postBody.filter_by.push({
field_name: paramName,
field_value: searchParams.get(paramName),
});
if (functionToCall !== null) {
functionToCall(searchParams.get(paramName) || '');
}
setShowFilterOptions(true);
}
}
);
if (additionalParams) { if (additionalParams) {
queryParamString += `&${additionalParams}`; queryParamString += `&${additionalParams}`;
} }
const reportMetadataBase64 = searchParams.get('report_metadata_base64'); HttpService.makeCallToBackend({
if (reportMetadataBase64) { path: `${processInstanceApiSearchPath}?${queryParamString}`,
const reportMetadata = JSON.parse(decodeBase64(reportMetadataBase64)) successCallback: setProcessInstancesFromResult,
httpMethod: 'POST',
failureCallback: stopRefreshing,
onUnauthorized: stopRefreshing,
postBody: {
report_metadata: reportMetadataBody,
},
});
}
function getReportMetadataWithReportHash() {
if (listHasBeenFiltered) {
return;
}
const reportHash = searchParams.get('report_hash');
if (reportHash) {
HttpService.makeCallToBackend({ HttpService.makeCallToBackend({
path: `${processInstanceApiSearchPath}?${queryParamString}`, path: `/process-instances/report-metadata/${reportHash}`,
successCallback: setProcessInstancesFromResult, successCallback: getProcessInstances,
httpMethod: 'POST',
failureCallback: stopRefreshing,
onUnauthorized: stopRefreshing,
postBody: {
report_metadata: reportMetadata,
// report_metadata: {
// filter_by: [
// {
// field_name: 'process_model_identifier',
// field_value: 'example/with-milestones',
// },
// ],
// },
},
}); });
} else {
getProcessInstances();
} }
} }
function processResultForProcessModels(result: any) { function processResultForProcessModels(result: any) {
const processModelFullIdentifierFromSearchParams =
getProcessModelFullIdentifierFromSearchParams(searchParams);
const selectionArray = result.results.map((item: any) => { const selectionArray = result.results.map((item: any) => {
const label = `${item.id}`; const label = `${item.id}`;
Object.assign(item, { label }); Object.assign(item, { label });
if (label === processModelFullIdentifierFromSearchParams) {
setProcessModelSelection(item);
}
return item; return item;
}); });
processModelSelectionItemsForUseEffect = selectionArray;
setProcessModelAvailableItems(selectionArray); setProcessModelAvailableItems(selectionArray);
const processStatusSelectedArray: string[] = [];
const processStatusAllOptionsArray = PROCESS_STATUSES.map( const processStatusAllOptionsArray = PROCESS_STATUSES.map(
(processStatusOption: any) => { (processStatusOption: any) => {
const regex = new RegExp(`\\b${processStatusOption}\\b`);
if ((searchParams.get('process_status') || '').match(regex)) {
processStatusSelectedArray.push(processStatusOption);
}
return processStatusOption; return processStatusOption;
} }
); );
setProcessStatusSelection(processStatusSelectedArray);
setProcessStatusAllOptions(processStatusAllOptionsArray); setProcessStatusAllOptions(processStatusAllOptionsArray);
getProcessInstances(); getReportMetadataWithReportHash();
} }
const checkFiltersAndRun = () => { const checkFiltersAndRun = () => {
if (filtersEnabled) { if (filtersEnabled) {
@ -509,7 +504,7 @@ export default function ProcessInstanceListTable({
successCallback: processResultForProcessModels, successCallback: processResultForProcessModels,
}); });
} else { } else {
getProcessInstances(); getReportMetadataWithReportHash();
} }
}; };
@ -540,59 +535,59 @@ export default function ProcessInstanceListTable({
processInstanceApiSearchPath, processInstanceApiSearchPath,
]); ]);
// This sets the filter data using the saved reports returned from the initial instance_list query. // // This sets the filter data using the saved reports returned from the initial instance_list query.
// This could probably be merged into the main useEffect but it works here now. // // This could probably be merged into the main useEffect but it works here now.
useEffect(() => { // useEffect(() => {
const filters = processInstanceFilters as any; // const filters = processInstanceFilters as any;
Object.keys(dateParametersToAlwaysFilterBy).forEach((paramName: string) => { // // Object.keys(dateParametersToAlwaysFilterBy).forEach((paramName: string) => {
const dateFunctionToCall = dateParametersToAlwaysFilterBy[paramName][0]; // // const dateFunctionToCall = dateParametersToAlwaysFilterBy[paramName][0];
const timeFunctionToCall = dateParametersToAlwaysFilterBy[paramName][1]; // // const timeFunctionToCall = dateParametersToAlwaysFilterBy[paramName][1];
const paramValue = filters[paramName]; // // const paramValue = filters[paramName];
dateFunctionToCall(''); // // dateFunctionToCall('');
timeFunctionToCall(''); // // timeFunctionToCall('');
if (paramValue) { // // if (paramValue) {
const dateString = convertSecondsToFormattedDateString( // // const dateString = convertSecondsToFormattedDateString(
paramValue as any // // paramValue as any
); // // );
dateFunctionToCall(dateString); // // dateFunctionToCall(dateString);
const timeString = convertSecondsToFormattedTimeHoursMinutes( // // const timeString = convertSecondsToFormattedTimeHoursMinutes(
paramValue as any // // paramValue as any
); // // );
timeFunctionToCall(timeString); // // timeFunctionToCall(timeString);
setShowFilterOptions(true); // // setShowFilterOptions(true);
} // // }
}); // // });
//
setProcessModelSelection(null); // // setProcessModelSelection(null);
processModelAvailableItems.forEach((item: any) => { // // processModelAvailableItems.forEach((item: any) => {
if (item.id === filters.process_model_identifier) { // // if (item.id === filters.process_model_identifier) {
setProcessModelSelection(item); // // setProcessModelSelection(item);
} // // }
}); // // });
//
if (filters.process_initiator_username) { // if (filters.process_initiator_username) {
const functionToCall = // const functionToCall =
parametersToGetFromSearchParams.process_initiator_username; // parametersToGetFromSearchParams.process_initiator_username;
functionToCall(filters.process_initiator_username); // functionToCall(filters.process_initiator_username);
} // }
//
const processStatusSelectedArray: string[] = []; // const processStatusSelectedArray: string[] = [];
if (filters.process_status) { // if (filters.process_status) {
PROCESS_STATUSES.forEach((processStatusOption: any) => { // PROCESS_STATUSES.forEach((processStatusOption: any) => {
const regex = new RegExp(`\\b${processStatusOption}\\b`); // const regex = new RegExp(`\\b${processStatusOption}\\b`);
if (filters.process_status.match(regex)) { // if (filters.process_status.match(regex)) {
processStatusSelectedArray.push(processStatusOption); // processStatusSelectedArray.push(processStatusOption);
} // }
}); // });
setShowFilterOptions(true); // setShowFilterOptions(true);
} // }
setProcessStatusSelection(processStatusSelectedArray); // // setProcessStatusSelection(processStatusSelectedArray);
}, [ // }, [
processInstanceFilters, // processInstanceFilters,
dateParametersToAlwaysFilterBy, // dateParametersToAlwaysFilterBy,
parametersToGetFromSearchParams, // parametersToGetFromSearchParams,
processModelAvailableItems, // processModelAvailableItems,
]); // ]);
const processInstanceReportSaveTag = () => { const processInstanceReportSaveTag = () => {
if (processInstanceReportJustSaved) { if (processInstanceReportJustSaved) {
@ -740,21 +735,6 @@ export default function ProcessInstanceListTable({
return; return;
} }
// "columns": [
// {"Header": "id", "accessor": "id"},
// {
// "Header": "process_model_display_name",
// "accessor": "process_model_display_name",
// },
// {"Header": "start_in_seconds", "accessor": "start_in_seconds"},
// {"Header": "end_in_seconds", "accessor": "end_in_seconds"},
// {"Header": "status", "accessor": "status"},
// ],
// "filter_by": [
// {"field_name": "initiated_by_me", "field_value": "true"},
// {"field_name": "has_terminal_status", "field_value": "true"},
// ],
// "order_by": ["-start_in_seconds", "-id"],
const postBody: ReportMetadata = { const postBody: ReportMetadata = {
columns: [], columns: [],
filter_by: [], filter_by: [],
@ -789,16 +769,9 @@ export default function ProcessInstanceListTable({
); );
} }
// console.log('reportColumns()', reportColumns())
// const reportColumnsBase64 = encodeBase64(JSON.stringify(reportColumns()));
// queryParamString += `&report_columns=${reportColumnsBase64}`;
postBody.columns = reportColumns(); postBody.columns = reportColumns();
// console.log('reportFilterBy()', reportFilterBy())
// const reportFilterByBase64 = encodeBase64(JSON.stringify(reportFilterBy()));
// queryParamString += `&report_filter_by=${reportFilterByBase64}`;
if (processInitiatorSelection) { if (processInitiatorSelection) {
// queryParamString += `&process_initiator_username=${processInitiatorSelection.username}`;
addFieldValueToReportMetadata( addFieldValueToReportMetadata(
postBody, postBody,
'process_initiator_username', 'process_initiator_username',
@ -828,11 +801,15 @@ export default function ProcessInstanceListTable({
// http://localhost:7001/admin/process-instances/for-me?per_page=50&page=1&report_metadata_base64=eyJjb2x1bW5zIjpudWxsLCJmaWx0ZXJfYnkiOlt7ImZpZWxkX25hbWUiOiJwcm9jZXNzX3N0YXR1cyIsImZpZWxkX3ZhbHVlIjoiY29tcGxldGUifV0sIm9yZGVyX2J5IjpbXX0%3D // http://localhost:7001/admin/process-instances/for-me?per_page=50&page=1&report_metadata_base64=eyJjb2x1bW5zIjpudWxsLCJmaWx0ZXJfYnkiOlt7ImZpZWxkX25hbWUiOiJwcm9jZXNzX3N0YXR1cyIsImZpZWxkX3ZhbHVlIjoiY29tcGxldGUifV0sIm9yZGVyX2J5IjpbXX0%3D
// const queryParamString = `per_page=${perPage}&page=${page}`; // const queryParamString = `per_page=${perPage}&page=${page}`;
setListHasBeenFiltered(true);
searchParams.set('per_page', perPage.toString()); searchParams.set('per_page', perPage.toString());
searchParams.set('page', page.toString()); searchParams.set('page', page.toString());
const reportMetadataBase64 = encodeBase64(JSON.stringify(postBody));
searchParams.set('report_metadata_base64', reportMetadataBase64); // const reportMetadataBase64 = encodeBase64(JSON.stringify(postBody));
// searchParams.set('report_metadata_base64', reportMetadataBase64);
setSearchParams(searchParams); setSearchParams(searchParams);
HttpService.makeCallToBackend({ HttpService.makeCallToBackend({
path: `${processInstanceApiSearchPath}?${queryParamString}`, path: `${processInstanceApiSearchPath}?${queryParamString}`,
httpMethod: 'POST', httpMethod: 'POST',