From ec0cf198d01329ee7bd5fff0ffa54a76621d450a Mon Sep 17 00:00:00 2001 From: jasquat Date: Mon, 1 May 2023 12:25:22 -0400 Subject: [PATCH] added links to filtered tables on homepage and added advanced options modal to use them w/ burnettk --- .../components/ProcessInstanceListTable.tsx | 335 ++++++++++++------ spiffworkflow-frontend/src/index.css | 6 + spiffworkflow-frontend/src/interfaces.ts | 5 +- .../src/routes/InProgressInstances.tsx | 75 ++-- 4 files changed, 281 insertions(+), 140 deletions(-) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 0e074ef9..0b36b6f1 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -1,23 +1,19 @@ -// TODO: -// add drop down for user_group_identifier and one for the 2 system reports: -// with_tasks_completed_by_me -// with_tasks_i_can_complete -// add checkbox to show with_oldest_open_task -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { - Link, - useNavigate, - useParams, - useSearchParams, -} from 'react-router-dom'; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; -// @ts-ignore -import { Close, AddAlt } from '@carbon/icons-react'; +import { Close, AddAlt, ArrowRight } from '@carbon/icons-react'; import { Button, ButtonSet, DatePicker, DatePickerInput, + Dropdown, Table, Grid, Column, @@ -32,7 +28,7 @@ import { ComboBox, TextInput, FormLabel, - // @ts-ignore + Checkbox, } from '@carbon/react'; import { useDebouncedCallback } from 'use-debounce'; import { @@ -102,6 +98,7 @@ type OwnProps = { canCompleteAllTasks?: boolean; showActionsColumn?: boolean; showLinkToReport?: boolean; + headerElement?: React.ReactElement; }; interface dateParameters { @@ -123,13 +120,13 @@ export default function ProcessInstanceListTable({ canCompleteAllTasks = false, showActionsColumn = false, showLinkToReport = false, + headerElement, }: OwnProps) { let processInstanceApiSearchPath = '/process-instances/for-me'; if (variant === 'all') { processInstanceApiSearchPath = '/process-instances'; } - const params = useParams(); const [searchParams, setSearchParams] = useSearchParams(); const navigate = useNavigate(); const { addError, removeError } = useAPIError(); @@ -147,8 +144,6 @@ export default function ProcessInstanceListTable({ const [reportMetadata, setReportMetadata] = useState(); const [pagination, setPagination] = useState(null); - const oneHourInSeconds = 3600; - const oneMonthInSeconds = oneHourInSeconds * 24 * 30; const [startFromDate, setStartFromDate] = useState(''); const [startToDate, setStartToDate] = useState(''); const [endFromDate, setEndFromDate] = useState(''); @@ -157,12 +152,13 @@ export default function ProcessInstanceListTable({ const [startToTime, setStartToTime] = useState(''); const [endFromTime, setEndFromTime] = useState(''); const [endToTime, setEndToTime] = useState(''); - const [showFilterOptions, setShowFilterOptions] = useState(false); const [startFromTimeInvalid, setStartFromTimeInvalid] = useState(false); const [startToTimeInvalid, setStartToTimeInvalid] = useState(false); const [endFromTimeInvalid, setEndFromTimeInvalid] = useState(false); const [endToTimeInvalid, setEndToTimeInvalid] = useState(false); + + const [showFilterOptions, setShowFilterOptions] = useState(false); const [requiresRefilter, setRequiresRefilter] = useState(false); const [lastColumnFilter, setLastColumnFilter] = useState(''); @@ -212,6 +208,18 @@ export default function ProcessInstanceListTable({ string | null >(null); + const [showAdvancedOptions, setShowAdvancedOptions] = + useState(false); + const [withOldestOpenTask, setWithOldestOpenTask] = useState(false); + const [systemReport, setSystemReport] = useState(null); + const [selectedUserGroup, setSelectedUserGroup] = useState( + null + ); + const [userGroups, setUserGroups] = useState([]); + const systemReportOptions: string[] = useMemo(() => { + return ['with_tasks_i_can_complete', 'with_tasks_completed_by_me']; + }, []); + const [reportHash, setReportHash] = useState(null); const [ @@ -274,19 +282,6 @@ export default function ProcessInstanceListTable({ 250 ); - const parametersToGetFromSearchParams = useMemo(() => { - const figureOutProcessInitiator = (processInitiatorSearchText: string) => { - searchForProcessInitiator(processInitiatorSearchText); - }; - - return { - process_model_identifier: null, - process_status: null, - process_initiator_username: figureOutProcessInitiator, - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const setProcessInstancesFromResult = useCallback((result: any) => { setRequiresRefilter(false); const processInstancesFromApi = result.results; @@ -319,19 +314,15 @@ export default function ProcessInstanceListTable({ } }, []); - // eslint-disable-next-line sonarjs/cognitive-complexity - useEffect(() => { - if (!permissionsLoaded) { - return undefined; - } + // we apparently cannot use a state set in a useEffect from within that same useEffect + // so use a variable instead + const processModelSelectionItemsForUseEffect = useRef([]); - // we apparently cannot use a state set in a useEffect from within that same useEffect - // so use a variable instead - let processModelSelectionItemsForUseEffect: ProcessModel[] = []; - - function getProcessInstances( + const getProcessInstances = useCallback( + ( processInstanceReport: ProcessInstanceReport | null = null - ) { + // eslint-disable-next-line sonarjs/cognitive-complexity + ) => { if (listHasBeenFiltered) { return; } @@ -359,6 +350,12 @@ export default function ProcessInstanceListTable({ ); } else if (reportFilter.field_name === 'process_initiator_username') { setProcessInitiatorSelection(reportFilter.field_value || ''); + } else if (reportFilter.field_name === 'with_oldest_open_task') { + setWithOldestOpenTask(reportFilter.field_value); + } else if (reportFilter.field_name === 'user_group_identifier') { + setSelectedUserGroup(reportFilter.field_value); + } else if (systemReportOptions.includes(reportFilter.field_name)) { + setSystemReport(reportFilter.field_name); } else if (reportFilter.field_name === 'process_model_identifier') { selectedProcessModelIdentifier = reportFilter.field_value || undefined; @@ -380,7 +377,7 @@ export default function ProcessInstanceListTable({ } } ); - processModelSelectionItemsForUseEffect.forEach( + processModelSelectionItemsForUseEffect.current.forEach( (processModel: ProcessModel) => { if (processModel.id === selectedProcessModelIdentifier) { setProcessModelSelection(processModel); @@ -412,6 +409,13 @@ export default function ProcessInstanceListTable({ }); } + if (filtersEnabled) { + HttpService.makeCallToBackend({ + path: `/user-groups/for-current-user`, + successCallback: setUserGroups, + }); + } + HttpService.makeCallToBackend({ path: `${processInstanceApiSearchPath}?${queryParamString}`, successCallback: setProcessInstancesFromResult, @@ -422,7 +426,28 @@ export default function ProcessInstanceListTable({ report_metadata: reportMetadataBodyToUse, }, }); + }, + [ + additionalReportFilters, + dateParametersToAlwaysFilterBy, + filtersEnabled, + listHasBeenFiltered, + paginationQueryParamPrefix, + perPageOptions, + processInstanceApiSearchPath, + processModelFullIdentifier, + searchParams, + setProcessInstancesFromResult, + stopRefreshing, + systemReportOptions, + ] + ); + + useEffect(() => { + if (!permissionsLoaded) { + return undefined; } + function getReportMetadataWithReportHash() { if (listHasBeenFiltered) { return; @@ -453,7 +478,7 @@ export default function ProcessInstanceListTable({ Object.assign(item, { label }); return item; }); - processModelSelectionItemsForUseEffect = selectionArray; + processModelSelectionItemsForUseEffect.current = selectionArray; setProcessModelAvailableItems(selectionArray); const processStatusAllOptionsArray = PROCESS_STATUSES.map( @@ -489,23 +514,12 @@ export default function ProcessInstanceListTable({ return undefined; }, [ autoReload, - searchParams, - params, - oneMonthInSeconds, - oneHourInSeconds, - dateParametersToAlwaysFilterBy, - parametersToGetFromSearchParams, filtersEnabled, - paginationQueryParamPrefix, - processModelFullIdentifier, - perPageOptions, - reportIdentifier, - additionalReportFilters, - processInstanceApiSearchPath, - permissionsLoaded, + getProcessInstances, listHasBeenFiltered, - setProcessInstancesFromResult, - stopRefreshing, + permissionsLoaded, + reportIdentifier, + searchParams, ]); const processInstanceReportSaveTag = () => { @@ -620,7 +634,7 @@ export default function ProcessInstanceListTable({ const insertOrUpdateFieldInReportMetadata = ( reportMetadataToUse: ReportMetadata, fieldName: string, - fieldValue: string + fieldValue: any ) => { removeFieldFromReportMetadata(reportMetadataToUse, fieldName); if (fieldValue) { @@ -644,7 +658,7 @@ export default function ProcessInstanceListTable({ return null; } - let newReportMetadata = null; + let newReportMetadata: ReportMetadata | null = null; if (reportMetadata) { newReportMetadata = { ...reportMetadata }; } @@ -677,41 +691,44 @@ export default function ProcessInstanceListTable({ endToSeconds ); - if (processStatusSelection.length > 0) { - insertOrUpdateFieldInReportMetadata( - newReportMetadata, - 'process_status', - processStatusSelection.join(',') - ); - } else { - removeFieldFromReportMetadata(newReportMetadata, 'process_status'); - } + insertOrUpdateFieldInReportMetadata( + newReportMetadata, + 'process_status', + processStatusSelection.length > 0 + ? processStatusSelection.join(',') + : null + ); + insertOrUpdateFieldInReportMetadata( + newReportMetadata, + 'process_model_identifier', + processModelSelection ? processModelSelection.id : null + ); + insertOrUpdateFieldInReportMetadata( + newReportMetadata, + 'process_initiator_username', + processInitiatorSelection + ); - if (processModelSelection) { - insertOrUpdateFieldInReportMetadata( - newReportMetadata, - 'process_model_identifier', - processModelSelection.id - ); - } else { - removeFieldFromReportMetadata( - newReportMetadata, - 'process_model_identifier' - ); - } + insertOrUpdateFieldInReportMetadata( + newReportMetadata, + 'with_oldest_open_task', + withOldestOpenTask + ); + insertOrUpdateFieldInReportMetadata( + newReportMetadata, + 'user_group_identifier', + selectedUserGroup + ); + systemReportOptions.forEach((systemReportOption: string) => { + if (newReportMetadata) { + insertOrUpdateFieldInReportMetadata( + newReportMetadata, + systemReportOption, + systemReport === systemReportOption + ); + } + }); - if (processInitiatorSelection) { - insertOrUpdateFieldInReportMetadata( - newReportMetadata, - 'process_initiator_username', - processInitiatorSelection - ); - } else { - removeFieldFromReportMetadata( - newReportMetadata, - 'process_initiator_username' - ); - } return newReportMetadata; }; @@ -843,14 +860,19 @@ export default function ProcessInstanceListTable({ clearFilters(); const selectedReport = selection.selectedItem; setProcessInstanceReportSelection(selectedReport); + removeError(); + setProcessInstanceReportJustSaved(mode || null); + setListHasBeenFiltered(false); let queryParamString = ''; if (selectedReport) { queryParamString = `?report_id=${selectedReport.id}`; - } - removeError(); - setProcessInstanceReportJustSaved(mode || null); + HttpService.makeCallToBackend({ + path: `/process-instances/report-metadata${queryParamString}`, + successCallback: getProcessInstances, + }); + } navigate(`${processInstanceListPathPrefix}${queryParamString}`); }; @@ -1181,6 +1203,75 @@ export default function ProcessInstanceListTable({ return null; }; + const handleAdvancedOptionsClose = () => { + setShowAdvancedOptions(false); + }; + + const advancedOptionsModal = () => { + if (!showAdvancedOptions) { + return null; + } + const formElements = ( + <> + + + item} + selectedItem={systemReport} + onChange={(value: any) => { + setSystemReport(value.selectedItem); + setRequiresRefilter(true); + }} + /> + + + item} + selectedItem={selectedUserGroup} + onChange={(value: any) => { + setSelectedUserGroup(value.selectedItem); + setRequiresRefilter(true); + }} + /> + + +
+ + + { + setWithOldestOpenTask(value.target.checked); + setRequiresRefilter(true); + }} + /> + + +
+ + ); + return ( + + {formElements} + + ); + }; + const filterOptions = () => { if (!showFilterOptions) { return null; @@ -1366,10 +1457,20 @@ export default function ProcessInstanceListTable({ - + {saveAsReportComponent()} {deleteReportComponent()} + + + ); @@ -1567,12 +1668,39 @@ export default function ProcessInstanceListTable({ return null; }; - const linkToReport = () => { - if (!showLinkToReport) { + const tableTitleLine = () => { + if (!showLinkToReport && !headerElement) { return null; } + let filterButtonLink = null; + if (showLinkToReport) { + filterButtonLink = ( + +