Fix that dreadful unknown "KeyError" exception that was cropping up.
Adding a bit of detail to the spiffworkflow exceptions when a duplicate process model is found. Disable the submit button on tasks after you click submit (avoid the double click and give users a better experience)
This commit is contained in:
parent
cd7c109a00
commit
d010c2bce6
|
@ -254,9 +254,9 @@ class BpmnParser(object):
|
||||||
def create_parser(self, node, filename=None, lane=None):
|
def create_parser(self, node, filename=None, lane=None):
|
||||||
parser = self.PROCESS_PARSER_CLASS(self, node, self.namespaces, filename=filename, lane=lane)
|
parser = self.PROCESS_PARSER_CLASS(self, node, self.namespaces, filename=filename, lane=lane)
|
||||||
if parser.get_id() in self.process_parsers:
|
if parser.get_id() in self.process_parsers:
|
||||||
raise ValidationException('Duplicate process ID', node=node, file_name=filename)
|
raise ValidationException(f'Duplicate process ID: {parser.get_id()}', node=node, file_name=filename)
|
||||||
if parser.get_name() in self.process_parsers_by_name:
|
if parser.get_name() in self.process_parsers_by_name:
|
||||||
raise ValidationException('Duplicate process name', node=node, file_name=filename)
|
raise ValidationException(f'Duplicate process name: {parser.get_name()}', node=node, file_name=filename)
|
||||||
self.process_parsers[parser.get_id()] = parser
|
self.process_parsers[parser.get_id()] = parser
|
||||||
self.process_parsers_by_name[parser.get_name()] = parser
|
self.process_parsers_by_name[parser.get_name()] = parser
|
||||||
|
|
||||||
|
|
|
@ -242,6 +242,10 @@ def handle_exception(exception: Exception) -> flask.wrappers.Response:
|
||||||
api_exception = None
|
api_exception = None
|
||||||
if isinstance(exception, ApiError):
|
if isinstance(exception, ApiError):
|
||||||
api_exception = exception
|
api_exception = exception
|
||||||
|
elif isinstance(exception, SpiffWorkflowException):
|
||||||
|
api_exception = ApiError.from_workflow_exception(
|
||||||
|
"unexpected_workflow_exception", "Unexpected Workflow Error", exception
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
api_exception = ApiError(
|
api_exception = ApiError(
|
||||||
error_code=error_code,
|
error_code=error_code,
|
||||||
|
|
|
@ -275,7 +275,7 @@ def task_show(process_instance_id: int, task_id: str) -> flask.wrappers.Response
|
||||||
) from exception
|
) from exception
|
||||||
|
|
||||||
if task.data:
|
if task.data:
|
||||||
_update_form_schema_with_task_data_as_needed(form_dict, task)
|
_update_form_schema_with_task_data_as_needed(form_dict, task, spiff_task)
|
||||||
|
|
||||||
if form_contents:
|
if form_contents:
|
||||||
task.form_schema = form_dict
|
task.form_schema = form_dict
|
||||||
|
@ -588,7 +588,9 @@ def _get_spiff_task_from_process_instance(
|
||||||
|
|
||||||
|
|
||||||
# originally from: https://bitcoden.com/answers/python-nested-dictionary-update-value-where-any-nested-key-matches
|
# originally from: https://bitcoden.com/answers/python-nested-dictionary-update-value-where-any-nested-key-matches
|
||||||
def _update_form_schema_with_task_data_as_needed(in_dict: dict, task: Task) -> None:
|
def _update_form_schema_with_task_data_as_needed(
|
||||||
|
in_dict: dict, task: Task, spiff_task: SpiffTask
|
||||||
|
) -> None:
|
||||||
"""Update_nested."""
|
"""Update_nested."""
|
||||||
if task.data is None:
|
if task.data is None:
|
||||||
return None
|
return None
|
||||||
|
@ -615,7 +617,7 @@ def _update_form_schema_with_task_data_as_needed(in_dict: dict, task: Task) -> N
|
||||||
f" '{task_data_var}' but it doesn't exist in"
|
f" '{task_data_var}' but it doesn't exist in"
|
||||||
" the Task Data."
|
" the Task Data."
|
||||||
),
|
),
|
||||||
task=task,
|
task=spiff_task,
|
||||||
)
|
)
|
||||||
raise (
|
raise (
|
||||||
ApiError.from_workflow_exception(
|
ApiError.from_workflow_exception(
|
||||||
|
@ -648,11 +650,11 @@ def _update_form_schema_with_task_data_as_needed(in_dict: dict, task: Task) -> N
|
||||||
|
|
||||||
in_dict[k] = options_for_react_json_schema_form
|
in_dict[k] = options_for_react_json_schema_form
|
||||||
elif isinstance(value, dict):
|
elif isinstance(value, dict):
|
||||||
_update_form_schema_with_task_data_as_needed(value, task)
|
_update_form_schema_with_task_data_as_needed(value, task, spiff_task)
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
for o in value:
|
for o in value:
|
||||||
if isinstance(o, dict):
|
if isinstance(o, dict):
|
||||||
_update_form_schema_with_task_data_as_needed(o, task)
|
_update_form_schema_with_task_data_as_needed(o, task, spiff_task)
|
||||||
|
|
||||||
|
|
||||||
def _get_potential_owner_usernames(assigned_user: AliasedClass) -> Any:
|
def _get_potential_owner_usernames(assigned_user: AliasedClass) -> Any:
|
||||||
|
|
|
@ -499,7 +499,10 @@ class ProcessModelService(FileSystemService):
|
||||||
if name is None:
|
if name is None:
|
||||||
raise ApiError(
|
raise ApiError(
|
||||||
error_code="missing_name_of_process_model",
|
error_code="missing_name_of_process_model",
|
||||||
message="Missing name of process model. It should be given",
|
message=(
|
||||||
|
"Missing name of process model. Path not found:"
|
||||||
|
f" {json_file_path}"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
process_model_info = ProcessModelInfo(
|
process_model_info = ProcessModelInfo(
|
||||||
|
|
|
@ -41,7 +41,10 @@ export default function TaskShow() {
|
||||||
// instead of passing the process model identifier in through the params
|
// instead of passing the process model identifier in through the params
|
||||||
HttpService.makeCallToBackend({
|
HttpService.makeCallToBackend({
|
||||||
path: url,
|
path: url,
|
||||||
successCallback: setUserTasks,
|
successCallback: (tasks: any) => {
|
||||||
|
setDisabled(false);
|
||||||
|
setUserTasks(tasks);
|
||||||
|
},
|
||||||
onUnauthorized: () => {},
|
onUnauthorized: () => {},
|
||||||
failureCallback: (error: any) => {
|
failureCallback: (error: any) => {
|
||||||
addError(error);
|
addError(error);
|
||||||
|
@ -59,7 +62,6 @@ export default function TaskShow() {
|
||||||
|
|
||||||
const processSubmitResult = (result: any) => {
|
const processSubmitResult = (result: any) => {
|
||||||
removeError();
|
removeError();
|
||||||
setDisabled(false);
|
|
||||||
if (result.ok) {
|
if (result.ok) {
|
||||||
navigate(`/tasks`);
|
navigate(`/tasks`);
|
||||||
} else if (result.process_instance_id) {
|
} else if (result.process_instance_id) {
|
||||||
|
@ -212,10 +214,16 @@ export default function TaskShow() {
|
||||||
reactFragmentToHideSubmitButton = <div />;
|
reactFragmentToHideSubmitButton = <div />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task.type === 'Manual Task' && task.state === 'READY') {
|
if (task.state === 'READY') {
|
||||||
|
let buttonText = 'Submit';
|
||||||
|
if (task.type === 'Manual Task') {
|
||||||
|
buttonText = 'Continue';
|
||||||
|
}
|
||||||
reactFragmentToHideSubmitButton = (
|
reactFragmentToHideSubmitButton = (
|
||||||
<div>
|
<div>
|
||||||
<Button type="submit">Continue</Button>
|
<Button type="submit" disabled={disabled}>
|
||||||
|
{buttonText}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -228,6 +236,7 @@ export default function TaskShow() {
|
||||||
<Grid fullWidth condensed>
|
<Grid fullWidth condensed>
|
||||||
<Column sm={4} md={5} lg={8}>
|
<Column sm={4} md={5} lg={8}>
|
||||||
<Form
|
<Form
|
||||||
|
disabled={disabled}
|
||||||
formData={taskData}
|
formData={taskData}
|
||||||
onSubmit={handleFormSubmit}
|
onSubmit={handleFormSubmit}
|
||||||
schema={jsonSchema}
|
schema={jsonSchema}
|
||||||
|
|
Loading…
Reference in New Issue