From 1851e86a976f8fcb53a5a6a24ff43922904aead7 Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 14 Nov 2022 17:00:28 -0500 Subject: [PATCH] turned the table list route into a table component w/ burnettk --- .../src/components/PaginationForTable.tsx | 2 +- .../components/ProcessInstanceListTable.tsx | 102 ++-- .../src/routes/ProcessInstanceList.tsx | 520 +----------------- .../src/routes/ProcessModelShow.tsx | 6 + 4 files changed, 78 insertions(+), 552 deletions(-) diff --git a/spiffworkflow-frontend/src/components/PaginationForTable.tsx b/spiffworkflow-frontend/src/components/PaginationForTable.tsx index 21813952..19d098ff 100644 --- a/spiffworkflow-frontend/src/components/PaginationForTable.tsx +++ b/spiffworkflow-frontend/src/components/PaginationForTable.tsx @@ -1,4 +1,4 @@ -import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useSearchParams } from 'react-router-dom'; // @ts-ignore import { Pagination } from '@carbon/react'; diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index f09ae711..81a416f3 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -41,9 +41,18 @@ import 'react-bootstrap-typeahead/css/Typeahead.css'; import 'react-bootstrap-typeahead/css/Typeahead.bs5.css'; import { PaginationObject, ProcessModel } from '../interfaces'; import ProcessModelSearch from './ProcessModelSearch'; -import ProcessBreadcrumb from './ProcessBreadcrumb'; -export default function ProcessInstanceList() { +type OwnProps = { + filtersEnabled?: boolean; + processModelFullIdentifier?: string; + paginationQueryParamPrefix?: string; +}; + +export default function ProcessInstanceListTable({ + filtersEnabled = true, + processModelFullIdentifier, + paginationQueryParamPrefix, +}: OwnProps) { const params = useParams(); const [searchParams] = useSearchParams(); const navigate = useNavigate(); @@ -99,7 +108,12 @@ export default function ProcessInstanceList() { setPagination(result.pagination); } function getProcessInstances() { - const { page, perPage } = getPageInfoFromSearchParams(searchParams); + const { page, perPage } = getPageInfoFromSearchParams( + searchParams, + undefined, + undefined, + paginationQueryParamPrefix + ); let queryParamString = `per_page=${perPage}&page=${page}`; Object.keys(parametersToAlwaysFilterBy).forEach((paramName: string) => { @@ -118,7 +132,12 @@ export default function ProcessInstanceList() { Object.keys(parametersToGetFromSearchParams).forEach( (paramName: string) => { - if (searchParams.get(paramName)) { + 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)}`; @@ -129,18 +148,19 @@ export default function ProcessInstanceList() { } } ); + HttpService.makeCallToBackend({ path: `/process-instances?${queryParamString}`, successCallback: setProcessInstancesFromResult, }); } function processResultForProcessModels(result: any) { - const processModelFullIdentifier = + const processModelFullIdentifierFromSearchParams = getProcessModelFullIdentifierFromSearchParams(searchParams); const selectionArray = result.results.map((item: any) => { const label = `${item.id}`; Object.assign(item, { label }); - if (label === processModelFullIdentifier) { + if (label === processModelFullIdentifierFromSearchParams) { setProcessModelSelection(item); } return item; @@ -163,11 +183,15 @@ export default function ProcessInstanceList() { getProcessInstances(); } - // populate process model selection - HttpService.makeCallToBackend({ - path: `/process-models?per_page=1000`, - successCallback: processResultForProcessModels, - }); + if (filtersEnabled) { + // populate process model selection + HttpService.makeCallToBackend({ + path: `/process-models?per_page=1000`, + successCallback: processResultForProcessModels, + }); + } else { + getProcessInstances(); + } }, [ searchParams, params, @@ -175,6 +199,7 @@ export default function ProcessInstanceList() { oneHourInSeconds, parametersToAlwaysFilterBy, parametersToGetFromSearchParams, + filtersEnabled, ]); // does the comparison, but also returns false if either argument @@ -196,7 +221,12 @@ export default function ProcessInstanceList() { const applyFilter = (event: any) => { event.preventDefault(); - const { page, perPage } = getPageInfoFromSearchParams(searchParams); + const { page, perPage } = getPageInfoFromSearchParams( + searchParams, + undefined, + undefined, + paginationQueryParamPrefix + ); let queryParamString = `per_page=${perPage}&page=${page}`; const startFromSeconds = convertDateStringToSeconds(startFrom); @@ -472,41 +502,16 @@ export default function ProcessInstanceList() { ); }; - const processInstanceBreadcrumbElement = () => { - const processModelFullIdentifier = - getProcessModelFullIdentifierFromSearchParams(searchParams); - if (processModelFullIdentifier === null) { - return null; - } - - return ( - - ); - }; - - const processInstanceTitleElement = () => { - return

Process Instances

; - }; - const toggleShowFilterOptions = () => { setShowFilterOptions(!showFilterOptions); }; - if (pagination) { - const { page, perPage } = getPageInfoFromSearchParams(searchParams); + const filterComponent = () => { + if (!filtersEnabled) { + return null; + } return ( <> - {processInstanceBreadcrumbElement()} - {processInstanceTitleElement()} {filterOptions()} + + ); + }; + + if (pagination) { + const { page, perPage } = getPageInfoFromSearchParams( + searchParams, + undefined, + undefined, + paginationQueryParamPrefix + ); + return ( + <> + {filterComponent()}
); diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceList.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceList.tsx index a09efebf..b6c08b21 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceList.tsx +++ b/spiffworkflow-frontend/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 ( - <> - - -