TaskShow had a useEffect that depended on params, that dependency caused an infinite request cycle when an error occured.
The same issue was happening on the ProcessInstanceListTable, and there it was being managed by a "SafelySetErrorMessage" function in one case, but would not be addressed in all possible cases. Reworked error handling into a context provider (APIErrorProvider) and hook (UseApiError) and removed the "(useContext as any)(ErrorContext)[1];" that felt a little off but that never was an actual problem.
This commit is contained in:
parent
bc8dd80d99
commit
2b6b053671
|
@ -20,8 +20,10 @@ services:
|
|||
retries: 10
|
||||
|
||||
spiffworkflow-backend:
|
||||
container_name: spiffworkflow-backend
|
||||
image: ghcr.io/sartography/spiffworkflow-backend:latest
|
||||
# container_name: spiffworkflow-backend
|
||||
build: ./spiffworkflow-backend/.
|
||||
# dockerfile: Dockerfile
|
||||
# image: ghcr.io/sartography/spiffworkflow-backend:latest
|
||||
depends_on:
|
||||
spiffworkflow-db:
|
||||
condition: service_healthy
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,6 +49,7 @@
|
|||
"react-bootstrap": "^2.5.0",
|
||||
"react-bootstrap-typeahead": "^6.0.0",
|
||||
"react-datepicker": "^4.8.0",
|
||||
"react-devtools": "^4.27.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.4.0",
|
||||
"react-jsonschema-form": "^1.8.1",
|
||||
|
|
|
@ -1,29 +1,20 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
// @ts-ignore
|
||||
import { Content } from '@carbon/react';
|
||||
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
import { defineAbility } from '@casl/ability';
|
||||
import ErrorContext from './contexts/ErrorContext';
|
||||
import NavigationBar from './components/NavigationBar';
|
||||
|
||||
import HomePageRoutes from './routes/HomePageRoutes';
|
||||
import ErrorBoundary from './components/ErrorBoundary';
|
||||
import AdminRoutes from './routes/AdminRoutes';
|
||||
import { ErrorForDisplay } from './interfaces';
|
||||
|
||||
import { AbilityContext } from './contexts/Can';
|
||||
import UserService from './services/UserService';
|
||||
import ErrorDisplay from './components/ErrorDisplay';
|
||||
import APIErrorProvider from './contexts/APIErrorContext';
|
||||
|
||||
export default function App() {
|
||||
const [errorObject, setErrorObject] = useState<ErrorForDisplay | null>(null);
|
||||
|
||||
const errorContextValueArray = useMemo(
|
||||
() => [errorObject, setErrorObject],
|
||||
[errorObject]
|
||||
);
|
||||
|
||||
if (!UserService.isLoggedIn()) {
|
||||
UserService.doLogin();
|
||||
return null;
|
||||
|
@ -35,7 +26,7 @@ export default function App() {
|
|||
<div className="cds--white">
|
||||
{/* @ts-ignore */}
|
||||
<AbilityContext.Provider value={ability}>
|
||||
<ErrorContext.Provider value={errorContextValueArray}>
|
||||
<APIErrorProvider>
|
||||
<BrowserRouter>
|
||||
<NavigationBar />
|
||||
<Content>
|
||||
|
@ -49,7 +40,7 @@ export default function App() {
|
|||
</ErrorBoundary>
|
||||
</Content>
|
||||
</BrowserRouter>
|
||||
</ErrorContext.Provider>
|
||||
</APIErrorProvider>
|
||||
</AbilityContext.Provider>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { useContext } from 'react';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { Notification } from './Notification';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
|
||||
function errorDetailDisplay(
|
||||
errorObject: any,
|
||||
|
@ -20,8 +19,8 @@ function errorDetailDisplay(
|
|||
}
|
||||
|
||||
export default function ErrorDisplay() {
|
||||
const [errorObject, setErrorObject] = (useContext as any)(ErrorContext);
|
||||
|
||||
const errorObject = useAPIError().error;
|
||||
const { removeError } = useAPIError()
|
||||
let errorTag = null;
|
||||
if (errorObject) {
|
||||
let sentryLinkTag = null;
|
||||
|
@ -50,7 +49,7 @@ export default function ErrorDisplay() {
|
|||
);
|
||||
const errorLine = errorDetailDisplay(errorObject, 'error_line', 'Context');
|
||||
let taskTrace = null;
|
||||
if ('task_trace' in errorObject && errorObject.task_trace.length > 1) {
|
||||
if (errorObject.task_trace && errorObject.task_trace.length > 1) {
|
||||
taskTrace = (
|
||||
<div className="error_info">
|
||||
<span className="error_title">Call Activity Trace:</span>
|
||||
|
@ -62,7 +61,7 @@ export default function ErrorDisplay() {
|
|||
errorTag = (
|
||||
<Notification
|
||||
title={title}
|
||||
onClose={() => setErrorObject(null)}
|
||||
onClose={() => (removeError())}
|
||||
type="error"
|
||||
>
|
||||
{message}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Link,
|
||||
useNavigate,
|
||||
|
@ -40,13 +40,11 @@ import {
|
|||
getProcessModelFullIdentifierFromSearchParams,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
refreshAtInterval,
|
||||
setErrorMessageSafely,
|
||||
} from '../helpers';
|
||||
|
||||
import PaginationForTable from './PaginationForTable';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import HttpService from '../services/HttpService';
|
||||
|
||||
import 'react-bootstrap-typeahead/css/Typeahead.css';
|
||||
|
@ -61,6 +59,7 @@ import {
|
|||
ReportMetadata,
|
||||
ReportFilter,
|
||||
User,
|
||||
ErrorForDisplay,
|
||||
} from '../interfaces';
|
||||
import ProcessModelSearch from './ProcessModelSearch';
|
||||
import ProcessInstanceReportSearch from './ProcessInstanceReportSearch';
|
||||
|
@ -68,6 +67,7 @@ import ProcessInstanceListDeleteReport from './ProcessInstanceListDeleteReport';
|
|||
import ProcessInstanceListSaveAsReport from './ProcessInstanceListSaveAsReport';
|
||||
import { FormatProcessModelDisplayName } from './MiniComponents';
|
||||
import { Notification } from './Notification';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
|
||||
const REFRESH_INTERVAL = 5;
|
||||
const REFRESH_TIMEOUT = 600;
|
||||
|
@ -110,6 +110,7 @@ export default function ProcessInstanceListTable({
|
|||
const params = useParams();
|
||||
const [searchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
const { addError, removeError } = useAPIError();
|
||||
|
||||
const [processInstances, setProcessInstances] = useState([]);
|
||||
const [reportMetadata, setReportMetadata] = useState<ReportMetadata | null>();
|
||||
|
@ -133,8 +134,6 @@ export default function ProcessInstanceListTable({
|
|||
const [endFromTimeInvalid, setEndFromTimeInvalid] = useState<boolean>(false);
|
||||
const [endToTimeInvalid, setEndToTimeInvalid] = useState<boolean>(false);
|
||||
|
||||
const [errorObject, setErrorObject] = (useContext as any)(ErrorContext);
|
||||
|
||||
const processInstanceListPathPrefix =
|
||||
variant === 'all'
|
||||
? '/admin/process-instances/all'
|
||||
|
@ -517,7 +516,7 @@ export default function ProcessInstanceListTable({
|
|||
}
|
||||
if (message !== '') {
|
||||
valid = false;
|
||||
setErrorMessageSafely(message, errorObject, setErrorObject);
|
||||
addError({ message } as ErrorForDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -579,7 +578,7 @@ export default function ProcessInstanceListTable({
|
|||
queryParamString += `&process_initiator_username=${processInitiatorSelection.username}`;
|
||||
}
|
||||
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
setProcessInstanceReportJustSaved(null);
|
||||
setProcessInstanceFilters({});
|
||||
navigate(`${processInstanceListPathPrefix}?${queryParamString}`);
|
||||
|
@ -679,7 +678,7 @@ export default function ProcessInstanceListTable({
|
|||
queryParamString = `?report_id=${selectedReport.id}`;
|
||||
}
|
||||
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
setProcessInstanceReportJustSaved(mode || null);
|
||||
navigate(`${processInstanceListPathPrefix}${queryParamString}`);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { useContext } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
|
@ -11,9 +10,9 @@ import {
|
|||
RecentProcessModel,
|
||||
} from '../interfaces';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { modifyProcessIdentifierForPathParam } from '../helpers';
|
||||
import { usePermissionFetcher } from '../hooks/PermissionService';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
|
||||
const storeRecentProcessModelInLocalStorage = (
|
||||
processModelForStorage: ProcessModel
|
||||
|
@ -78,7 +77,7 @@ export default function ProcessInstanceRun({
|
|||
checkPermissions = true,
|
||||
}: OwnProps) {
|
||||
const navigate = useNavigate();
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
const { addError, removeError } = useAPIError();
|
||||
const modifiedProcessModelId = modifyProcessIdentifierForPathParam(
|
||||
processModel.id
|
||||
);
|
||||
|
@ -105,12 +104,12 @@ export default function ProcessInstanceRun({
|
|||
};
|
||||
|
||||
const processModelRun = (processInstance: any) => {
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
storeRecentProcessModelInLocalStorage(processModel);
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/process-instances/${modifiedProcessModelId}/${processInstance.id}/run`,
|
||||
successCallback: onProcessInstanceRun,
|
||||
failureCallback: setErrorObject,
|
||||
failureCallback: addError,
|
||||
httpMethod: 'POST',
|
||||
});
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ import BpmnViewer from 'bpmn-js/lib/Viewer';
|
|||
import {
|
||||
BpmnPropertiesPanelModule,
|
||||
BpmnPropertiesProviderModule,
|
||||
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'bpmn... Remove this comment to see the full error message
|
||||
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'bpmn... RemoFve this comment to see the full error message
|
||||
} from 'bpmn-js-properties-panel';
|
||||
|
||||
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'dmn-... Remove this comment to see the full error message
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import React, { createContext, useState, useCallback } from 'react';
|
||||
import { ErrorForDisplay } from '../interfaces';
|
||||
|
||||
type ErrorContextType = {
|
||||
error: null | ErrorForDisplay;
|
||||
addError: Function;
|
||||
removeError: Function;
|
||||
};
|
||||
export const APIErrorContext = createContext<ErrorContextType>({
|
||||
error: null,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
addError: () => {},
|
||||
removeError: () => {},
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line react/prop-types
|
||||
export default function APIErrorProvider({ children }) {
|
||||
const [error, setError] = useState<ErrorForDisplay | null>(null);
|
||||
const addError = (errorForDisplay: ErrorForDisplay | null) => {
|
||||
setError(errorForDisplay);
|
||||
console.log('Adding an error.', errorForDisplay);
|
||||
}
|
||||
const removeError = () => setError(null);
|
||||
|
||||
const contextValue = {
|
||||
error,
|
||||
addError: useCallback(
|
||||
(newError: ErrorForDisplay | null) => addError(newError),
|
||||
[]
|
||||
),
|
||||
removeError: useCallback(() => removeError(), []),
|
||||
};
|
||||
|
||||
return (
|
||||
<APIErrorContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</APIErrorContext.Provider>
|
||||
);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
import { createContext } from 'react';
|
||||
|
||||
// @ts-expect-error TS(2554) FIXME: Expected 1 arguments, but got 0.
|
||||
const ErrorContext = createContext();
|
||||
export default ErrorContext;
|
|
@ -258,20 +258,6 @@ export const getBpmnProcessIdentifiers = (rootBpmnElement: any) => {
|
|||
return childProcesses;
|
||||
};
|
||||
|
||||
// Setting the error message state to the same string is still considered a change
|
||||
// and re-renders the page so check the message first to avoid that.
|
||||
export const setErrorMessageSafely = (
|
||||
newErrorMessageString: string,
|
||||
oldErrorMessage: ErrorForDisplay,
|
||||
errorMessageSetter: any
|
||||
) => {
|
||||
if (oldErrorMessage && oldErrorMessage.message === newErrorMessageString) {
|
||||
return null;
|
||||
}
|
||||
errorMessageSetter({ message: newErrorMessageString });
|
||||
return null;
|
||||
};
|
||||
|
||||
export const isInteger = (str: string | number) => {
|
||||
return /^\d+$/.test(str.toString());
|
||||
};
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// src/common/hooks/useAPIError/index.js
|
||||
import { useContext } from 'react';
|
||||
import { APIErrorContext } from '../contexts/APIErrorContext';
|
||||
|
||||
function useAPIError() {
|
||||
const { error, addError, removeError } = useContext(APIErrorContext);
|
||||
return { error, addError, removeError };
|
||||
}
|
||||
|
||||
export default useAPIError;
|
|
@ -182,6 +182,7 @@ export interface ErrorForDisplay {
|
|||
task_id?: string;
|
||||
line_number?: number;
|
||||
file_name?: string;
|
||||
task_trace?: [string];
|
||||
}
|
||||
|
||||
export interface AuthenticationParam {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Routes, Route, useLocation } from 'react-router-dom';
|
||||
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import ProcessGroupList from './ProcessGroupList';
|
||||
import ProcessGroupShow from './ProcessGroupShow';
|
||||
import ProcessGroupNew from './ProcessGroupNew';
|
||||
|
@ -17,21 +17,21 @@ import ProcessInstanceReportList from './ProcessInstanceReportList';
|
|||
import ProcessInstanceReportNew from './ProcessInstanceReportNew';
|
||||
import ProcessInstanceReportEdit from './ProcessInstanceReportEdit';
|
||||
import ReactFormEditor from './ReactFormEditor';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import ProcessInstanceLogList from './ProcessInstanceLogList';
|
||||
import MessageInstanceList from './MessageInstanceList';
|
||||
import Configuration from './Configuration';
|
||||
import JsonSchemaFormBuilder from './JsonSchemaFormBuilder';
|
||||
import ProcessModelNewExperimental from './ProcessModelNewExperimental';
|
||||
import ProcessInstanceFindById from './ProcessInstanceFindById';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
|
||||
export default function AdminRoutes() {
|
||||
const location = useLocation();
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
const { removeError } = useAPIError();
|
||||
|
||||
useEffect(() => {
|
||||
setErrorObject(null);
|
||||
}, [location, setErrorObject]);
|
||||
removeError();
|
||||
}, [location, removeError]);
|
||||
|
||||
if (UserService.hasRole(['admin'])) {
|
||||
return (
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
// @ts-ignore
|
||||
import { Table } from '@carbon/react';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
import { AuthenticationItem } from '../interfaces';
|
||||
import HttpService from '../services/HttpService';
|
||||
import UserService from '../services/UserService';
|
||||
|
||||
export default function AuthenticationList() {
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
|
||||
const { addError } = useAPIError();
|
||||
const [authenticationList, setAuthenticationList] = useState<
|
||||
AuthenticationItem[] | null
|
||||
>(null);
|
||||
|
@ -26,9 +25,9 @@ export default function AuthenticationList() {
|
|||
HttpService.makeCallToBackend({
|
||||
path: `/authentications`,
|
||||
successCallback: processResult,
|
||||
failureCallback: setErrorObject,
|
||||
failureCallback: addError,
|
||||
});
|
||||
}, [setErrorObject]);
|
||||
}, [addError]);
|
||||
|
||||
const buildTable = () => {
|
||||
if (authenticationList) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
||||
// @ts-ignore
|
||||
import { Tabs, TabList, Tab } from '@carbon/react';
|
||||
import { Can } from '@casl/react';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
import SecretList from './SecretList';
|
||||
import SecretNew from './SecretNew';
|
||||
import SecretShow from './SecretShow';
|
||||
|
@ -14,7 +14,7 @@ import { usePermissionFetcher } from '../hooks/PermissionService';
|
|||
|
||||
export default function Configuration() {
|
||||
const location = useLocation();
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
const { removeError } = useAPIError();
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState<number>(0);
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
@ -26,13 +26,13 @@ export default function Configuration() {
|
|||
const { ability } = usePermissionFetcher(permissionRequestData);
|
||||
|
||||
useEffect(() => {
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
let newSelectedTabIndex = 0;
|
||||
if (location.pathname.match(/^\/admin\/configuration\/authentications\b/)) {
|
||||
newSelectedTabIndex = 1;
|
||||
}
|
||||
setSelectedTabIndex(newSelectedTabIndex);
|
||||
}, [location, setErrorObject]);
|
||||
}, [location, removeError]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
||||
// @ts-ignore
|
||||
import { Tabs, TabList, Tab } from '@carbon/react';
|
||||
import TaskShow from './TaskShow';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
import MyTasks from './MyTasks';
|
||||
import GroupedTasks from './GroupedTasks';
|
||||
import CompletedInstances from './CompletedInstances';
|
||||
|
@ -11,12 +11,12 @@ import CreateNewInstance from './CreateNewInstance';
|
|||
|
||||
export default function HomePageRoutes() {
|
||||
const location = useLocation();
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
const { removeError } = useAPIError();
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState<number>(0);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
let newSelectedTabIndex = 0;
|
||||
if (location.pathname.match(/^\/tasks\/completed-instances\b/)) {
|
||||
newSelectedTabIndex = 1;
|
||||
|
@ -24,7 +24,7 @@ export default function HomePageRoutes() {
|
|||
newSelectedTabIndex = 2;
|
||||
}
|
||||
setSelectedTabIndex(newSelectedTabIndex);
|
||||
}, [location, setErrorObject]);
|
||||
}, [location, removeError]);
|
||||
|
||||
const renderTabs = () => {
|
||||
if (location.pathname.match(/^\/tasks\/\d+\/\b/)) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import Editor from '@monaco-editor/react';
|
||||
import {
|
||||
useParams,
|
||||
|
@ -38,7 +38,6 @@ import {
|
|||
unModifyProcessIdentifierForPathParam,
|
||||
} from '../helpers';
|
||||
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
||||
import {
|
||||
PermissionsToCheck,
|
||||
|
@ -49,6 +48,7 @@ import {
|
|||
import { usePermissionFetcher } from '../hooks/PermissionService';
|
||||
import ProcessInstanceClass from '../classes/ProcessInstanceClass';
|
||||
import TaskListTable from '../components/TaskListTable';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
|
||||
type OwnProps = {
|
||||
variant: string;
|
||||
|
@ -75,8 +75,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
useState<boolean>(false);
|
||||
const [displayDetails, setDisplayDetails] = useState<boolean>(false);
|
||||
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
|
||||
const { addError, removeError } = useAPIError();
|
||||
const unModifiedProcessModelId = unModifyProcessIdentifierForPathParam(
|
||||
`${params.process_model_id}`
|
||||
);
|
||||
|
@ -151,11 +150,11 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
}
|
||||
}
|
||||
}, [
|
||||
params,
|
||||
// targetUris,
|
||||
// params,
|
||||
modifiedProcessModelId,
|
||||
permissionsLoaded,
|
||||
ability,
|
||||
targetUris,
|
||||
searchParams,
|
||||
taskListPath,
|
||||
variant,
|
||||
|
@ -684,7 +683,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
setSelectingEvent(false);
|
||||
initializeTaskDataToDisplay(taskToDisplay);
|
||||
setEventPayload('{}');
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
};
|
||||
|
||||
const taskDataStringToObject = (dataString: string) => {
|
||||
|
@ -699,16 +698,12 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
refreshPage();
|
||||
};
|
||||
|
||||
const saveTaskDataFailure = (result: any) => {
|
||||
setErrorObject({ message: result.message });
|
||||
};
|
||||
|
||||
const saveTaskData = () => {
|
||||
if (!taskToDisplay) {
|
||||
return;
|
||||
}
|
||||
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
|
||||
// taskToUse is copy of taskToDisplay, with taskDataToDisplay in data attribute
|
||||
const taskToUse: any = { ...taskToDisplay, data: taskDataToDisplay };
|
||||
|
@ -716,7 +711,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
path: `${targetUris.processInstanceTaskListDataPath}/${taskToUse.id}`,
|
||||
httpMethod: 'PUT',
|
||||
successCallback: saveTaskDataResult,
|
||||
failureCallback: saveTaskDataFailure,
|
||||
failureCallback: addError,
|
||||
postBody: {
|
||||
new_task_data: taskToUse.data,
|
||||
},
|
||||
|
@ -730,7 +725,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
path: `/send-event/${modifiedProcessModelId}/${params.process_instance_id}`,
|
||||
httpMethod: 'POST',
|
||||
successCallback: saveTaskDataResult,
|
||||
failureCallback: saveTaskDataFailure,
|
||||
failureCallback: addError,
|
||||
postBody: eventToSend,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
generatePath,
|
||||
useNavigate,
|
||||
|
@ -25,7 +25,7 @@ import MDEditor from '@uiw/react-md-editor';
|
|||
import ReactDiagramEditor from '../components/ReactDiagramEditor';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
import { makeid, modifyProcessIdentifierForPathParam } from '../helpers';
|
||||
import {
|
||||
CarbonComboBoxProcessSelection,
|
||||
|
@ -100,7 +100,7 @@ export default function ProcessModelEditDiagram() {
|
|||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
const { addError, removeError } = useAPIError();
|
||||
const [processModelFile, setProcessModelFile] = useState<ProcessFile | null>(
|
||||
null
|
||||
);
|
||||
|
@ -176,7 +176,7 @@ export default function ProcessModelEditDiagram() {
|
|||
|
||||
const saveDiagram = (bpmnXML: any, fileName = params.file_name) => {
|
||||
setDisplaySaveFileMessage(false);
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
setBpmnXmlForDiagramRendering(bpmnXML);
|
||||
|
||||
let url = `/process-models/${modifiedProcessModelId}/files`;
|
||||
|
@ -202,7 +202,7 @@ export default function ProcessModelEditDiagram() {
|
|||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
successCallback: navigateToProcessModelFile,
|
||||
failureCallback: setErrorObject,
|
||||
failureCallback: addError,
|
||||
httpMethod,
|
||||
postBody: formData,
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom';
|
||||
import {
|
||||
Add,
|
||||
|
@ -32,7 +32,8 @@ import {
|
|||
import { Can } from '@casl/react';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
|
||||
import {
|
||||
getGroupFromModifiedModelId,
|
||||
modifyProcessIdentifierForPathParam,
|
||||
|
@ -52,7 +53,7 @@ import { Notification } from '../components/Notification';
|
|||
|
||||
export default function ProcessModelShow() {
|
||||
const params = useParams();
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
const { addError, removeError } = useAPIError();
|
||||
|
||||
const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
|
||||
const [processInstance, setProcessInstance] =
|
||||
|
@ -148,7 +149,7 @@ export default function ProcessModelShow() {
|
|||
!('file_contents' in processModelFile) ||
|
||||
processModelFile.file_contents === undefined
|
||||
) {
|
||||
setErrorObject({
|
||||
addError({
|
||||
message: `Could not file file contents for file: ${processModelFile.name}`,
|
||||
});
|
||||
return;
|
||||
|
@ -169,7 +170,7 @@ export default function ProcessModelShow() {
|
|||
};
|
||||
|
||||
const downloadFile = (fileName: string) => {
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
const processModelPath = `process-models/${modifiedProcessModelId}`;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/${processModelPath}/files/${fileName}`,
|
||||
|
@ -374,7 +375,7 @@ export default function ProcessModelShow() {
|
|||
|
||||
const doFileUpload = (event: any) => {
|
||||
event.preventDefault();
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
const url = `/process-models/${modifiedProcessModelId}/files`;
|
||||
const formData = new FormData();
|
||||
formData.append('file', filesToUpload[0]);
|
||||
|
@ -384,7 +385,7 @@ export default function ProcessModelShow() {
|
|||
successCallback: onUploadedCallback,
|
||||
httpMethod: 'POST',
|
||||
postBody: formData,
|
||||
failureCallback: setErrorObject,
|
||||
failureCallback: addError,
|
||||
});
|
||||
setFilesToUpload(null);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import Editor from '@monaco-editor/react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
// @ts-ignore
|
||||
|
@ -8,16 +8,14 @@ import HttpService from '../services/HttpService';
|
|||
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
||||
import { modifyProcessIdentifierForPathParam } from '../helpers';
|
||||
import { ProcessFile } from '../interfaces';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { Notification } from '../components/Notification';
|
||||
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
// NOTE: This is mostly the same as ProcessModelEditDiagram and if we go this route could
|
||||
// possibly be merged into it. I'm leaving as a separate file now in case it does
|
||||
// end up diverging greatly
|
||||
export default function ReactFormEditor() {
|
||||
const params = useParams();
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
|
||||
const { addError, removeError } = useAPIError();
|
||||
const [showFileNameEditor, setShowFileNameEditor] = useState(false);
|
||||
const [newFileName, setNewFileName] = useState('');
|
||||
const searchParams = useSearchParams()[0];
|
||||
|
@ -87,7 +85,7 @@ export default function ReactFormEditor() {
|
|||
};
|
||||
|
||||
const saveFile = () => {
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
setDisplaySaveFileMessage(false);
|
||||
|
||||
let url = `/process-models/${modifiedProcessModelId}/files`;
|
||||
|
@ -116,7 +114,7 @@ export default function ReactFormEditor() {
|
|||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
successCallback: navigateToProcessModelFile,
|
||||
failureCallback: setErrorObject,
|
||||
failureCallback: addError,
|
||||
httpMethod,
|
||||
postBody: formData,
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import validator from '@rjsf/validator-ajv8';
|
||||
|
||||
|
@ -17,7 +17,7 @@ import remarkGfm from 'remark-gfm';
|
|||
// eslint-disable-next-line import/no-named-as-default
|
||||
import Form from '../themes/carbon';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import useAPIError from '../hooks/UseApiError';
|
||||
import { modifyProcessIdentifierForPathParam } from '../helpers';
|
||||
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
||||
import { PermissionsToCheck } from '../interfaces';
|
||||
|
@ -29,7 +29,7 @@ export default function TaskShow() {
|
|||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const setErrorObject = (useContext as any)(ErrorContext)[1];
|
||||
const { addError, removeError } = useAPIError();
|
||||
|
||||
const { targetUris } = useUriListForPermissions();
|
||||
const permissionRequestData: PermissionsToCheck = {
|
||||
|
@ -39,48 +39,55 @@ export default function TaskShow() {
|
|||
permissionRequestData
|
||||
);
|
||||
|
||||
const processResult = (result: any) => {
|
||||
setTask(result);
|
||||
const url = `/task-data/${modifyProcessIdentifierForPathParam(
|
||||
result.process_model_identifier
|
||||
)}/${params.process_instance_id}`;
|
||||
if (
|
||||
result.process_model_identifier &&
|
||||
ability.can('GET', url)
|
||||
// Assure we get a valid process model identifier back
|
||||
) {
|
||||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
successCallback: setUserTasks,
|
||||
failureCallback: (error: any) => {
|
||||
addError(error);
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (permissionsLoaded) {
|
||||
const processResult = (result: any) => {
|
||||
setTask(result);
|
||||
if (ability.can('GET', targetUris.processInstanceTaskListDataPath)) {
|
||||
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: setErrorObject,
|
||||
failureCallback: addError,
|
||||
});
|
||||
}
|
||||
}, [params, permissionsLoaded, ability, targetUris]);
|
||||
}, [permissionsLoaded, ability]); // params and targetUris (which deps on params) cause this to re-fire in an infinite loop on error.
|
||||
|
||||
const processSubmitResult = (result: any) => {
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
if (result.ok) {
|
||||
navigate(`/tasks`);
|
||||
} else if (result.process_instance_id) {
|
||||
navigate(`/tasks/${result.process_instance_id}/${result.id}`);
|
||||
} else {
|
||||
setErrorObject(`Received unexpected error: ${result.message}`);
|
||||
addError(result);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFormSubmit = (event: any) => {
|
||||
setErrorObject(null);
|
||||
removeError();
|
||||
const dataToSubmit = event.formData;
|
||||
delete dataToSubmit.isManualTask;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/tasks/${params.process_instance_id}/${params.task_id}`,
|
||||
successCallback: processSubmitResult,
|
||||
failureCallback: setErrorObject,
|
||||
failureCallback: addError,
|
||||
httpMethod: 'PUT',
|
||||
postBody: dataToSubmit,
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue