diff --git a/src/components/MyCompletedInstances.tsx b/src/components/MyCompletedInstances.tsx new file mode 100644 index 0000000..fe66529 --- /dev/null +++ b/src/components/MyCompletedInstances.tsx @@ -0,0 +1,13 @@ +import ProcessInstanceListTable from './ProcessInstanceListTable'; + +const paginationQueryParamPrefix = 'my_completed_instances'; + +export default function MyCompletedInstances() { + return ( + + ); +} diff --git a/src/components/PaginationForTable.tsx b/src/components/PaginationForTable.tsx index 3b65c78..70da531 100644 --- a/src/components/PaginationForTable.tsx +++ b/src/components/PaginationForTable.tsx @@ -1,4 +1,4 @@ -import { useNavigate } from 'react-router-dom'; +import { useSearchParams } from 'react-router-dom'; // @ts-ignore import { Pagination } from '@carbon/react'; @@ -13,8 +13,7 @@ type OwnProps = { perPageOptions?: number[]; pagination: PaginationObject | null; tableToDisplay: any; - queryParamString?: string; - path: string; + paginationQueryParamPrefix?: string; }; export default function PaginationForTable({ @@ -23,16 +22,21 @@ export default function PaginationForTable({ perPageOptions, pagination, tableToDisplay, - queryParamString = '', - path, + paginationQueryParamPrefix, }: OwnProps) { const PER_PAGE_OPTIONS = [2, 10, 50, 100]; - const navigate = useNavigate(); + const [searchParams, setSearchParams] = useSearchParams(); + const paginationQueryParamPrefixToUse = paginationQueryParamPrefix + ? `${paginationQueryParamPrefix}_` + : ''; const updateRows = (args: any) => { const newPage = args.page; const { pageSize } = args; - navigate(`${path}?page=${newPage}&per_page=${pageSize}${queryParamString}`); + + searchParams.set(`${paginationQueryParamPrefixToUse}page`, newPage); + searchParams.set(`${paginationQueryParamPrefixToUse}per_page`, pageSize); + setSearchParams(searchParams); }; if (pagination) { diff --git a/src/components/ProcessInstanceListTable.tsx b/src/components/ProcessInstanceListTable.tsx new file mode 100644 index 0000000..ceb0e99 --- /dev/null +++ b/src/components/ProcessInstanceListTable.tsx @@ -0,0 +1,557 @@ +import { useContext, useEffect, useMemo, useState } from 'react'; +import { + Link, + useNavigate, + useParams, + useSearchParams, +} from 'react-router-dom'; + +// @ts-ignore +import { Filter } from '@carbon/icons-react'; +import { + Button, + ButtonSet, + DatePicker, + DatePickerInput, + Table, + Grid, + Column, + MultiSelect, + TableHeader, + TableHead, + TableRow, + // @ts-ignore +} from '@carbon/react'; +import { PROCESS_STATUSES, DATE_FORMAT, DATE_FORMAT_CARBON } from '../config'; +import { + convertDateStringToSeconds, + convertSecondsToFormattedDate, + getPageInfoFromSearchParams, + getProcessModelFullIdentifierFromSearchParams, + modifyProcessModelPath, +} 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'; +import 'react-bootstrap-typeahead/css/Typeahead.bs5.css'; +import { PaginationObject, ProcessModel } from '../interfaces'; +import ProcessModelSearch from './ProcessModelSearch'; + +type OwnProps = { + filtersEnabled?: boolean; + processModelFullIdentifier?: string; + paginationQueryParamPrefix?: string; + perPageOptions?: number[]; +}; + +export default function ProcessInstanceListTable({ + filtersEnabled = true, + processModelFullIdentifier, + paginationQueryParamPrefix, + perPageOptions, +}: OwnProps) { + const params = useParams(); + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); + + const [processInstances, setProcessInstances] = useState([]); + const [reportMetadata, setReportMetadata] = useState({}); + const [pagination, setPagination] = useState(null); + + const oneHourInSeconds = 3600; + const oneMonthInSeconds = oneHourInSeconds * 24 * 30; + const [startFrom, setStartFrom] = useState(''); + const [startTo, setStartTo] = useState(''); + const [endFrom, setEndFrom] = useState(''); + const [endTo, setEndTo] = useState(''); + const [showFilterOptions, setShowFilterOptions] = useState(false); + + const setErrorMessage = (useContext as any)(ErrorContext)[1]; + + const [processStatusAllOptions, setProcessStatusAllOptions] = useState( + [] + ); + const [processStatusSelection, setProcessStatusSelection] = useState< + string[] + >([]); + const [processModelAvailableItems, setProcessModelAvailableItems] = useState< + ProcessModel[] + >([]); + const [processModelSelection, setProcessModelSelection] = + useState(null); + + const parametersToAlwaysFilterBy = useMemo(() => { + return { + start_from: setStartFrom, + start_to: setStartTo, + end_from: setEndFrom, + end_to: setEndTo, + }; + }, [setStartFrom, setStartTo, setEndFrom, setEndTo]); + + const parametersToGetFromSearchParams = useMemo(() => { + return { + process_model_identifier: null, + process_status: null, + }; + }, []); + + // eslint-disable-next-line sonarjs/cognitive-complexity + useEffect(() => { + function setProcessInstancesFromResult(result: any) { + const processInstancesFromApi = result.results; + setProcessInstances(processInstancesFromApi); + setReportMetadata(result.report_metadata); + setPagination(result.pagination); + } + function getProcessInstances() { + // eslint-disable-next-line prefer-const + let { page, perPage } = getPageInfoFromSearchParams( + searchParams, + undefined, + undefined, + paginationQueryParamPrefix + ); + if (perPageOptions && !perPageOptions.includes(perPage)) { + // eslint-disable-next-line prefer-destructuring + perPage = perPageOptions[1]; + } + let queryParamString = `per_page=${perPage}&page=${page}`; + + Object.keys(parametersToAlwaysFilterBy).forEach((paramName: string) => { + // @ts-expect-error TS(7053) FIXME: + const functionToCall = parametersToAlwaysFilterBy[paramName]; + const searchParamValue = searchParams.get(paramName); + if (searchParamValue) { + queryParamString += `&${paramName}=${searchParamValue}`; + const dateString = convertSecondsToFormattedDate( + searchParamValue as any + ); + functionToCall(dateString); + setShowFilterOptions(true); + } + }); + + Object.keys(parametersToGetFromSearchParams).forEach( + (paramName: string) => { + if ( + paramName === 'process_model_identifier' && + processModelFullIdentifier + ) { + queryParamString += `&process_model_identifier=${processModelFullIdentifier}`; + } else if (searchParams.get(paramName)) { + // @ts-expect-error TS(7053) FIXME: + const functionToCall = parametersToGetFromSearchParams[paramName]; + queryParamString += `&${paramName}=${searchParams.get(paramName)}`; + if (functionToCall !== null) { + functionToCall(searchParams.get(paramName) || ''); + } + setShowFilterOptions(true); + } + } + ); + + HttpService.makeCallToBackend({ + path: `/process-instances?${queryParamString}`, + successCallback: setProcessInstancesFromResult, + }); + } + function processResultForProcessModels(result: any) { + const processModelFullIdentifierFromSearchParams = + getProcessModelFullIdentifierFromSearchParams(searchParams); + const selectionArray = result.results.map((item: any) => { + const label = `${item.id}`; + Object.assign(item, { label }); + if (label === processModelFullIdentifierFromSearchParams) { + setProcessModelSelection(item); + } + return item; + }); + setProcessModelAvailableItems(selectionArray); + + const processStatusSelectedArray: string[] = []; + const processStatusAllOptionsArray = PROCESS_STATUSES.map( + (processStatusOption: any) => { + const regex = new RegExp(`\\b${processStatusOption}\\b`); + if ((searchParams.get('process_status') || '').match(regex)) { + processStatusSelectedArray.push(processStatusOption); + } + return processStatusOption; + } + ); + setProcessStatusSelection(processStatusSelectedArray); + setProcessStatusAllOptions(processStatusAllOptionsArray); + + getProcessInstances(); + } + + if (filtersEnabled) { + // populate process model selection + HttpService.makeCallToBackend({ + path: `/process-models?per_page=1000`, + successCallback: processResultForProcessModels, + }); + } else { + getProcessInstances(); + } + }, [ + searchParams, + params, + oneMonthInSeconds, + oneHourInSeconds, + parametersToAlwaysFilterBy, + parametersToGetFromSearchParams, + filtersEnabled, + paginationQueryParamPrefix, + processModelFullIdentifier, + perPageOptions, + ]); + + // does the comparison, but also returns false if either argument + // is not truthy and therefore not comparable. + const isTrueComparison = (param1: any, operation: any, param2: any) => { + if (param1 && param2) { + switch (operation) { + case '<': + return param1 < param2; + case '>': + return param1 > param2; + default: + return false; + } + } else { + return false; + } + }; + + const applyFilter = (event: any) => { + event.preventDefault(); + const { page, perPage } = getPageInfoFromSearchParams( + searchParams, + undefined, + undefined, + paginationQueryParamPrefix + ); + let queryParamString = `per_page=${perPage}&page=${page}`; + + const startFromSeconds = convertDateStringToSeconds(startFrom); + const endFromSeconds = convertDateStringToSeconds(endFrom); + const startToSeconds = convertDateStringToSeconds(startTo); + const endToSeconds = convertDateStringToSeconds(endTo); + if (isTrueComparison(startFromSeconds, '>', startToSeconds)) { + setErrorMessage({ + message: '"Start date from" cannot be after "start date to"', + }); + return; + } + if (isTrueComparison(endFromSeconds, '>', endToSeconds)) { + setErrorMessage({ + message: '"End date from" cannot be after "end date to"', + }); + return; + } + if (isTrueComparison(startFromSeconds, '>', endFromSeconds)) { + setErrorMessage({ + message: '"Start date from" cannot be after "end date from"', + }); + return; + } + if (isTrueComparison(startToSeconds, '>', endToSeconds)) { + setErrorMessage({ + message: '"Start date to" cannot be after "end date to"', + }); + return; + } + + if (startFromSeconds) { + queryParamString += `&start_from=${startFromSeconds}`; + } + if (startToSeconds) { + queryParamString += `&start_to=${startToSeconds}`; + } + if (endFromSeconds) { + queryParamString += `&end_from=${endFromSeconds}`; + } + if (endToSeconds) { + queryParamString += `&end_to=${endToSeconds}`; + } + if (processStatusSelection.length > 0) { + queryParamString += `&process_status=${processStatusSelection}`; + } + + if (processModelSelection) { + queryParamString += `&process_model_identifier=${processModelSelection.id}`; + } + + setErrorMessage(null); + navigate(`/admin/process-instances?${queryParamString}`); + }; + + const dateComponent = ( + labelString: any, + name: any, + initialDate: any, + onChangeFunction: any + ) => { + return ( + + { + onChangeFunction(dateChangeEvent.srcElement.value); + }} + value={initialDate} + /> + + ); + }; + + const processStatusSearch = () => { + return ( + { + setProcessStatusSelection(selection.selectedItems); + }} + itemToString={(item: any) => { + return item || ''; + }} + selectionFeedback="top-after-reopen" + selectedItems={processStatusSelection} + /> + ); + }; + + const clearFilters = () => { + setProcessModelSelection(null); + setProcessStatusSelection([]); + setStartFrom(''); + setStartTo(''); + setEndFrom(''); + setEndTo(''); + }; + + const filterOptions = () => { + if (!showFilterOptions) { + return null; + } + return ( + <> + + + + setProcessModelSelection(selection.selectedItem) + } + processModels={processModelAvailableItems} + selectedItem={processModelSelection} + /> + + {processStatusSearch()} + + + + {dateComponent( + 'Start date from', + 'start-from', + startFrom, + setStartFrom + )} + + + {dateComponent('Start date to', 'start-to', startTo, setStartTo)} + + + {dateComponent('End date from', 'end-from', endFrom, setEndFrom)} + + + {dateComponent('End date to', 'end-to', endTo, setEndTo)} + + + + + + + + + + + + ); + }; + + const buildTable = () => { + const headerLabels: Record = { + id: 'Process Instance Id', + process_model_identifier: 'Process Model', + start_in_seconds: 'Start Time', + end_in_seconds: 'End Time', + status: 'Status', + spiff_step: 'SpiffWorkflow Step', + }; + const getHeaderLabel = (header: string) => { + return headerLabels[header] ?? header; + }; + const headers = (reportMetadata as any).columns.map((column: any) => { + // return {getHeaderLabel((column as any).Header)}; + return getHeaderLabel((column as any).Header); + }); + + const formatProcessInstanceId = (row: any, id: any) => { + const modifiedProcessModelId: String = modifyProcessModelPath( + row.process_model_identifier + ); + return ( + + {id} + + ); + }; + const formatProcessModelIdentifier = (_row: any, identifier: any) => { + return ( + + {identifier} + + ); + }; + const formatSecondsForDisplay = (_row: any, seconds: any) => { + return convertSecondsToFormattedDate(seconds) || '-'; + }; + const defaultFormatter = (_row: any, value: any) => { + return value; + }; + + const columnFormatters: Record = { + id: formatProcessInstanceId, + process_model_identifier: formatProcessModelIdentifier, + start_in_seconds: formatSecondsForDisplay, + end_in_seconds: formatSecondsForDisplay, + }; + const formattedColumn = (row: any, column: any) => { + const formatter = columnFormatters[column.accessor] ?? defaultFormatter; + const value = row[column.accessor]; + if (column.accessor === 'status') { + return ( + + {formatter(row, value)} + + ); + } + return {formatter(row, value)}; + }; + + const rows = processInstances.map((row: any) => { + const currentRow = (reportMetadata as any).columns.map((column: any) => { + return formattedColumn(row, column); + }); + return {currentRow}; + }); + + return ( + + + + {headers.map((header: any) => ( + {header} + ))} + + + {rows} +
+ ); + }; + + const toggleShowFilterOptions = () => { + setShowFilterOptions(!showFilterOptions); + }; + + const filterComponent = () => { + if (!filtersEnabled) { + return null; + } + return ( + <> + + + + + + ); + }); + return ( + + + + + + + + + + + + + + + {rows} +
Process ModelProcess InstanceTask NameProcess Started ByProcess Instance StatusAssigned GroupProcess StartedProcess UpdatedActions
+ ); + }; + + const tasksComponent = () => { + if (pagination && pagination.total < 1) { + return null; + } + const { page, perPage } = getPageInfoFromSearchParams( + searchParams, + PER_PAGE_FOR_TASKS_ON_HOME_PAGE, + undefined, + paginationQueryParamPrefix + ); + return ( + <> +

Tasks waiting for my groups

+ + + ); + }; + + if (pagination) { + return tasksComponent(); + } + return null; +} diff --git a/src/helpers.tsx b/src/helpers.tsx index 383c3e0..37286c8 100644 --- a/src/helpers.tsx +++ b/src/helpers.tsx @@ -79,11 +79,20 @@ export const objectIsEmpty = (obj: object) => { export const getPageInfoFromSearchParams = ( searchParams: any, defaultPerPage: string | number = DEFAULT_PER_PAGE, - defaultPage: string | number = DEFAULT_PAGE + defaultPage: string | number = DEFAULT_PAGE, + paginationQueryParamPrefix: string | null = null ) => { - const page = parseInt(searchParams.get('page') || defaultPage.toString(), 10); + const paginationQueryParamPrefixToUse = paginationQueryParamPrefix + ? `${paginationQueryParamPrefix}_` + : ''; + const page = parseInt( + searchParams.get(`${paginationQueryParamPrefixToUse}page`) || + defaultPage.toString(), + 10 + ); const perPage = parseInt( - searchParams.get('per_page') || defaultPerPage.toString(), + searchParams.get(`${paginationQueryParamPrefixToUse}per_page`) || + defaultPerPage.toString(), 10 ); diff --git a/src/routes/CompletedInstances.tsx b/src/routes/CompletedInstances.tsx new file mode 100644 index 0000000..237c21f --- /dev/null +++ b/src/routes/CompletedInstances.tsx @@ -0,0 +1,5 @@ +import MyCompletedInstances from '../components/MyCompletedInstances'; + +export default function CompletedInstances() { + return ; +} diff --git a/src/routes/GroupedTasks.tsx b/src/routes/GroupedTasks.tsx index 7312bc5..a08959c 100644 --- a/src/routes/GroupedTasks.tsx +++ b/src/routes/GroupedTasks.tsx @@ -1,12 +1,15 @@ -import MyTasksForProcessesStartedByOthers from '../components/MyTasksForProcessesStartedByOthers'; import TasksForMyOpenProcesses from '../components/TasksForMyOpenProcesses'; +import TasksWaitingForMe from '../components/TasksWaitingForMe'; +import TasksForWaitingForMyGroups from '../components/TasksWaitingForMyGroups'; export default function GroupedTasks() { return ( <>
- + +
+ ); } diff --git a/src/routes/HomePageRoutes.tsx b/src/routes/HomePageRoutes.tsx index d02cb9d..9f4bc69 100644 --- a/src/routes/HomePageRoutes.tsx +++ b/src/routes/HomePageRoutes.tsx @@ -6,6 +6,7 @@ import TaskShow from './TaskShow'; import ErrorContext from '../contexts/ErrorContext'; import MyTasks from './MyTasks'; import GroupedTasks from './GroupedTasks'; +import CompletedInstances from './CompletedInstances'; export default function HomePageRoutes() { const location = useLocation(); @@ -18,6 +19,8 @@ export default function HomePageRoutes() { let newSelectedTabIndex = 0; if (location.pathname.match(/^\/tasks\/grouped\b/)) { newSelectedTabIndex = 1; + } else if (location.pathname.match(/^\/tasks\/completed-instances\b/)) { + newSelectedTabIndex = 2; } setSelectedTabIndex(newSelectedTabIndex); }, [location, setErrorMessage]); @@ -28,6 +31,9 @@ export default function HomePageRoutes() { navigate('/tasks/my-tasks')}>My Tasks navigate('/tasks/grouped')}>Grouped Tasks + navigate('/tasks/completed-instances')}> + Completed Instances +
@@ -36,6 +42,7 @@ export default function HomePageRoutes() { } /> } /> } /> + } /> ); diff --git a/src/routes/MessageInstanceList.tsx b/src/routes/MessageInstanceList.tsx index 83ea1e4..09d2831 100644 --- a/src/routes/MessageInstanceList.tsx +++ b/src/routes/MessageInstanceList.tsx @@ -94,14 +94,8 @@ export default function MessageInstanceList() { if (pagination) { const { page, perPage } = getPageInfoFromSearchParams(searchParams); - let queryParamString = ''; let breadcrumbElement = null; if (searchParams.get('process_instance_id')) { - queryParamString += `&process_group_id=${searchParams.get( - 'process_group_id' - )}&process_model_id=${searchParams.get( - 'process_model_id' - )}&process_instance_id=${searchParams.get('process_instance_id')}`; breadcrumbElement = ( ); diff --git a/src/routes/MyTasks.tsx b/src/routes/MyTasks.tsx index 6b6eabd..a2183db 100644 --- a/src/routes/MyTasks.tsx +++ b/src/routes/MyTasks.tsx @@ -152,7 +152,6 @@ export default function MyTasks() { perPageOptions={[2, PER_PAGE_FOR_TASKS_ON_HOME_PAGE, 25]} pagination={pagination} tableToDisplay={buildTable()} - path="/tasks" /> ); diff --git a/src/routes/ProcessGroupList.tsx b/src/routes/ProcessGroupList.tsx index e84ec53..63e9050 100644 --- a/src/routes/ProcessGroupList.tsx +++ b/src/routes/ProcessGroupList.tsx @@ -109,7 +109,6 @@ export default function ProcessGroupList() { perPage={perPage} pagination={pagination as any} tableToDisplay={buildTable()} - path="/admin/process-groups" /> ); diff --git a/src/routes/ProcessGroupShow.tsx b/src/routes/ProcessGroupShow.tsx index a35b003..39ae461 100644 --- a/src/routes/ProcessGroupShow.tsx +++ b/src/routes/ProcessGroupShow.tsx @@ -170,7 +170,6 @@ export default function ProcessGroupShow() { perPage={perPage} pagination={modelPagination} tableToDisplay={buildModelTable()} - path={`/admin/process-groups/${processGroup.id}`} /> )}
@@ -182,7 +181,6 @@ export default function ProcessGroupShow() { perPage={perPage} pagination={groupPagination} tableToDisplay={buildGroupTable()} - path={`/admin/process-groups/${processGroup.id}`} /> )} diff --git a/src/routes/ProcessInstanceList.tsx b/src/routes/ProcessInstanceList.tsx index 338b04e..b6c08b2 100644 --- a/src/routes/ProcessInstanceList.tsx +++ b/src/routes/ProcessInstanceList.tsx @@ -1,482 +1,15 @@ -import { useContext, useEffect, useMemo, useState } from 'react'; -import { - Link, - useNavigate, - useParams, - useSearchParams, -} from 'react-router-dom'; +import { useSearchParams } from 'react-router-dom'; -// @ts-ignore -import { Filter } from '@carbon/icons-react'; -import { - Button, - ButtonSet, - DatePicker, - DatePickerInput, - Table, - Grid, - Column, - MultiSelect, - TableHeader, - TableHead, - TableRow, - // @ts-ignore -} from '@carbon/react'; -import { PROCESS_STATUSES, DATE_FORMAT, DATE_FORMAT_CARBON } from '../config'; -import { - convertDateStringToSeconds, - convertSecondsToFormattedDate, - getPageInfoFromSearchParams, - getProcessModelFullIdentifierFromSearchParams, - modifyProcessModelPath, -} from '../helpers'; - -import PaginationForTable from '../components/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'; import 'react-bootstrap-typeahead/css/Typeahead.bs5.css'; -import { PaginationObject, ProcessModel } from '../interfaces'; -import ProcessModelSearch from '../components/ProcessModelSearch'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; +import ProcessInstanceListTable from '../components/ProcessInstanceListTable'; +import { getProcessModelFullIdentifierFromSearchParams } from '../helpers'; export default function ProcessInstanceList() { - const params = useParams(); const [searchParams] = useSearchParams(); - const navigate = useNavigate(); - - const [processInstances, setProcessInstances] = useState([]); - const [reportMetadata, setReportMetadata] = useState({}); - const [pagination, setPagination] = useState(null); - - const oneHourInSeconds = 3600; - const oneMonthInSeconds = oneHourInSeconds * 24 * 30; - const [startFrom, setStartFrom] = useState(''); - const [startTo, setStartTo] = useState(''); - const [endFrom, setEndFrom] = useState(''); - const [endTo, setEndTo] = useState(''); - const [showFilterOptions, setShowFilterOptions] = useState(false); - - const setErrorMessage = (useContext as any)(ErrorContext)[1]; - - const [processStatusAllOptions, setProcessStatusAllOptions] = useState( - [] - ); - const [processStatusSelection, setProcessStatusSelection] = useState< - string[] - >([]); - const [processModelAvailableItems, setProcessModelAvailableItems] = useState< - ProcessModel[] - >([]); - const [processModelSelection, setProcessModelSelection] = - useState(null); - - const parametersToAlwaysFilterBy = useMemo(() => { - return { - start_from: setStartFrom, - start_to: setStartTo, - end_from: setEndFrom, - end_to: setEndTo, - }; - }, [setStartFrom, setStartTo, setEndFrom, setEndTo]); - - const parametersToGetFromSearchParams = useMemo(() => { - return { - process_model_identifier: null, - process_status: null, - }; - }, []); - - // eslint-disable-next-line sonarjs/cognitive-complexity - useEffect(() => { - function setProcessInstancesFromResult(result: any) { - const processInstancesFromApi = result.results; - setProcessInstances(processInstancesFromApi); - setReportMetadata(result.report_metadata); - setPagination(result.pagination); - } - function getProcessInstances() { - const { page, perPage } = getPageInfoFromSearchParams(searchParams); - let queryParamString = `per_page=${perPage}&page=${page}`; - - Object.keys(parametersToAlwaysFilterBy).forEach((paramName: string) => { - // @ts-expect-error TS(7053) FIXME: - const functionToCall = parametersToAlwaysFilterBy[paramName]; - const searchParamValue = searchParams.get(paramName); - if (searchParamValue) { - queryParamString += `&${paramName}=${searchParamValue}`; - const dateString = convertSecondsToFormattedDate( - searchParamValue as any - ); - functionToCall(dateString); - setShowFilterOptions(true); - } - }); - - Object.keys(parametersToGetFromSearchParams).forEach( - (paramName: string) => { - if (searchParams.get(paramName)) { - // @ts-expect-error TS(7053) FIXME: - const functionToCall = parametersToGetFromSearchParams[paramName]; - queryParamString += `&${paramName}=${searchParams.get(paramName)}`; - if (functionToCall !== null) { - functionToCall(searchParams.get(paramName) || ''); - } - setShowFilterOptions(true); - } - } - ); - HttpService.makeCallToBackend({ - path: `/process-instances?${queryParamString}`, - successCallback: setProcessInstancesFromResult, - }); - } - function processResultForProcessModels(result: any) { - const processModelFullIdentifier = - getProcessModelFullIdentifierFromSearchParams(searchParams); - const selectionArray = result.results.map((item: any) => { - const label = `${item.id}`; - Object.assign(item, { label }); - if (label === processModelFullIdentifier) { - setProcessModelSelection(item); - } - return item; - }); - setProcessModelAvailableItems(selectionArray); - - const processStatusSelectedArray: string[] = []; - const processStatusAllOptionsArray = PROCESS_STATUSES.map( - (processStatusOption: any) => { - const regex = new RegExp(`\\b${processStatusOption}\\b`); - if ((searchParams.get('process_status') || '').match(regex)) { - processStatusSelectedArray.push(processStatusOption); - } - return processStatusOption; - } - ); - setProcessStatusSelection(processStatusSelectedArray); - setProcessStatusAllOptions(processStatusAllOptionsArray); - - getProcessInstances(); - } - - // populate process model selection - HttpService.makeCallToBackend({ - path: `/process-models?per_page=1000`, - successCallback: processResultForProcessModels, - }); - }, [ - searchParams, - params, - oneMonthInSeconds, - oneHourInSeconds, - parametersToAlwaysFilterBy, - parametersToGetFromSearchParams, - ]); - - // does the comparison, but also returns false if either argument - // is not truthy and therefore not comparable. - const isTrueComparison = (param1: any, operation: any, param2: any) => { - if (param1 && param2) { - switch (operation) { - case '<': - return param1 < param2; - case '>': - return param1 > param2; - default: - return false; - } - } else { - return false; - } - }; - - const applyFilter = (event: any) => { - event.preventDefault(); - const { page, perPage } = getPageInfoFromSearchParams(searchParams); - let queryParamString = `per_page=${perPage}&page=${page}`; - - const startFromSeconds = convertDateStringToSeconds(startFrom); - const endFromSeconds = convertDateStringToSeconds(endFrom); - const startToSeconds = convertDateStringToSeconds(startTo); - const endToSeconds = convertDateStringToSeconds(endTo); - if (isTrueComparison(startFromSeconds, '>', startToSeconds)) { - setErrorMessage({ - message: '"Start date from" cannot be after "start date to"', - }); - return; - } - if (isTrueComparison(endFromSeconds, '>', endToSeconds)) { - setErrorMessage({ - message: '"End date from" cannot be after "end date to"', - }); - return; - } - if (isTrueComparison(startFromSeconds, '>', endFromSeconds)) { - setErrorMessage({ - message: '"Start date from" cannot be after "end date from"', - }); - return; - } - if (isTrueComparison(startToSeconds, '>', endToSeconds)) { - setErrorMessage({ - message: '"Start date to" cannot be after "end date to"', - }); - return; - } - - if (startFromSeconds) { - queryParamString += `&start_from=${startFromSeconds}`; - } - if (startToSeconds) { - queryParamString += `&start_to=${startToSeconds}`; - } - if (endFromSeconds) { - queryParamString += `&end_from=${endFromSeconds}`; - } - if (endToSeconds) { - queryParamString += `&end_to=${endToSeconds}`; - } - if (processStatusSelection.length > 0) { - queryParamString += `&process_status=${processStatusSelection}`; - } - - if (processModelSelection) { - queryParamString += `&process_model_identifier=${processModelSelection.id}`; - } - - setErrorMessage(null); - navigate(`/admin/process-instances?${queryParamString}`); - }; - - const dateComponent = ( - labelString: any, - name: any, - initialDate: any, - onChangeFunction: any - ) => { - return ( - - { - onChangeFunction(dateChangeEvent.srcElement.value); - }} - value={initialDate} - /> - - ); - }; - const processStatusSearch = () => { - return ( - { - setProcessStatusSelection(selection.selectedItems); - }} - itemToString={(item: any) => { - return item || ''; - }} - selectionFeedback="top-after-reopen" - selectedItems={processStatusSelection} - /> - ); - }; - const clearFilters = () => { - setProcessModelSelection(null); - setProcessStatusSelection([]); - setStartFrom(''); - setStartTo(''); - setEndFrom(''); - setEndTo(''); - }; - const filterOptions = () => { - if (!showFilterOptions) { - return null; - } - return ( - <> - - - - setProcessModelSelection(selection.selectedItem) - } - processModels={processModelAvailableItems} - selectedItem={processModelSelection} - /> - - {processStatusSearch()} - - - - {dateComponent( - 'Start date from', - 'start-from', - startFrom, - setStartFrom - )} - - - {dateComponent('Start date to', 'start-to', startTo, setStartTo)} - - - {dateComponent('End date from', 'end-from', endFrom, setEndFrom)} - - - {dateComponent('End date to', 'end-to', endTo, setEndTo)} - - - - - - - - - - - - ); - }; - const toggleShowFilterOptions = () => { - setShowFilterOptions(!showFilterOptions); - }; - const filterComponent = () => { - return ( - <> - - -