From 0a7052e5d2d8bd884f04fe79317abf00aefb0384 Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 17 Nov 2022 11:52:57 -0500 Subject: [PATCH 01/11] a little cleanup to forms w/ burnettk --- spiffworkflow-frontend/package-lock.json | 68 ----------------- .../components/ProcessInstanceListTable.tsx | 43 +++++++---- .../src/routes/TaskShow.tsx | 75 ++++++++++++------- .../BaseInputTemplate/BaseInputTemplate.tsx | 3 + 4 files changed, 81 insertions(+), 108 deletions(-) diff --git a/spiffworkflow-frontend/package-lock.json b/spiffworkflow-frontend/package-lock.json index 4898b19c..0dfe841a 100644 --- a/spiffworkflow-frontend/package-lock.json +++ b/spiffworkflow-frontend/package-lock.json @@ -24,7 +24,6 @@ "@rjsf/mui": "^5.0.0-beta.13", "@rjsf/utils": "^5.0.0-beta.13", "@rjsf/validator-ajv6": "^5.0.0-beta.13", - "@rjsf/validator-ajv8": "^5.0.0-beta.13", "@tanstack/react-table": "^8.2.2", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", @@ -4950,23 +4949,6 @@ "@rjsf/utils": "^5.0.0-beta.1" } }, - "node_modules/@rjsf/validator-ajv8": { - "version": "5.0.0-beta.13", - "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.0.0-beta.13.tgz", - "integrity": "sha512-/hrYbiwgCvEqw1Z7YZTWvd+ZAiX5vSN0WAI2hJTJTqKuCTcIH0fqNDCaOg3FBR38BL7seZrUmibIUcPU66iJ1w==", - "dependencies": { - "ajv-formats": "^2.1.1", - "ajv8": "npm:ajv@^8.11.0", - "lodash": "^4.17.15", - "lodash-es": "^4.17.15" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@rjsf/utils": "^5.0.0-beta.12" - } - }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -6840,27 +6822,6 @@ "ajv": "^6.9.1" } }, - "node_modules/ajv8": { - "name": "ajv", - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv8/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -34883,17 +34844,6 @@ "lodash-es": "^4.17.15" } }, - "@rjsf/validator-ajv8": { - "version": "5.0.0-beta.13", - "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.0.0-beta.13.tgz", - "integrity": "sha512-/hrYbiwgCvEqw1Z7YZTWvd+ZAiX5vSN0WAI2hJTJTqKuCTcIH0fqNDCaOg3FBR38BL7seZrUmibIUcPU66iJ1w==", - "requires": { - "ajv-formats": "^2.1.1", - "ajv8": "npm:ajv@^8.11.0", - "lodash": "^4.17.15", - "lodash-es": "^4.17.15" - } - }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -36367,24 +36317,6 @@ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "requires": {} }, - "ajv8": { - "version": "npm:ajv@8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "dependencies": { - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - } - } - }, "ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 5c7786c0..407ac307 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -20,12 +20,16 @@ import { TableHeader, TableHead, TableRow, + TimePicker, + TimePickerSelect, + SelectItem, // @ts-ignore } from '@carbon/react'; import { PROCESS_STATUSES, DATE_FORMAT, DATE_FORMAT_CARBON } from '../config'; import { convertDateStringToSeconds, convertSecondsToFormattedDate, + convertSecondsToFormattedDateTime, getPageInfoFromSearchParams, getProcessModelFullIdentifierFromSearchParams, modifyProcessModelPath, @@ -345,21 +349,32 @@ export default function ProcessInstanceListTable({ onChangeFunction: any ) => { return ( - - { - onChangeFunction(dateChangeEvent.srcElement.value); + <> + + { + onChangeFunction(dateChangeEvent.srcElement.value); + }} + value={initialDate} + /> + + { + console.log('event', event); }} - value={initialDate} /> - + ); }; @@ -493,7 +508,7 @@ export default function ProcessInstanceListTable({ ); }; const formatSecondsForDisplay = (_row: any, seconds: any) => { - return convertSecondsToFormattedDate(seconds) || '-'; + return convertSecondsToFormattedDateTime(seconds) || '-'; }; const defaultFormatter = (_row: any, value: any) => { return value; diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx index 9da0e30a..1309b8f3 100644 --- a/spiffworkflow-frontend/src/routes/TaskShow.tsx +++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from 'react'; -import { Link, useNavigate, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; // FIXME: npm install @rjsf/validator-ajv8 and use it as soon as // rawErrors is fixed. @@ -9,8 +9,14 @@ import { Link, useNavigate, useParams } from 'react-router-dom'; // https://github.com/rjsf-team/react-jsonschema-form/blob/main/docs/api-reference/uiSchema.md talks about rawErrors import validator from '@rjsf/validator-ajv6'; -// @ts-ignore -import { Button, Stack } from '@carbon/react'; +import { + TabList, + Tab, + Tabs, + Grid, + Column, + // @ts-ignore +} from '@carbon/react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; @@ -73,39 +79,52 @@ export default function TaskShow() { const buildTaskNavigation = () => { let userTasksElement; + let selectedTabIndex = 0; if (userTasks) { userTasksElement = (userTasks as any).map(function getUserTasksElement( - userTask: any + userTask: any, + index: number ) { const taskUrl = `/tasks/${params.process_instance_id}/${userTask.id}`; if (userTask.id === params.task_id) { - return {userTask.name}; + selectedTabIndex = index; + return {userTask.title}; } if (userTask.state === 'COMPLETED') { return ( - - {userTask.name} - + navigate(taskUrl)} + data-qa={`form-nav-${userTask.name}`} + > + {userTask.title} + ); } if (userTask.state === 'FUTURE') { - return {userTask.name}; + return {userTask.title}; } if (userTask.state === 'READY') { return ( - - {userTask.name} - Current - + navigate(taskUrl)} + data-qa={`form-nav-${userTask.name}`} + > + {userTask.title} + ); } return null; }); } return ( - - - {userTasksElement} - + + + {userTasksElement} + + ); }; @@ -149,15 +168,19 @@ export default function TaskShow() { } return ( -
- {reactFragmentToHideSubmitButton} -
+ + +
+ {reactFragmentToHideSubmitButton} +
+
+
); }; @@ -175,7 +198,7 @@ export default function TaskShow() { ); }; - if (task) { + if (task && userTasks) { const taskToUse = task as any; let statusString = ''; if (taskToUse.state !== 'READY') { diff --git a/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx b/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx index 90cc3f0f..0670c69d 100644 --- a/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx +++ b/spiffworkflow-frontend/src/themes/carbon/BaseInputTemplate/BaseInputTemplate.tsx @@ -82,6 +82,9 @@ export default function BaseInputTemplate< } else if (schema && schema.title) { labelToUse = schema.title; } + if (required) { + labelToUse = `${labelToUse}*`; + } let invalid = false; let errorMessageForField = null; From 2a1c3109777b34ae609e844017a7112307e0eefe Mon Sep 17 00:00:00 2001 From: burnettk Date: Thu, 17 Nov 2022 13:48:11 -0500 Subject: [PATCH 02/11] just use the word id in the header and add tooltip --- .../src/components/ProcessInstanceListTable.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 5c7786c0..5ce8dda1 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -455,7 +455,7 @@ export default function ProcessInstanceListTable({ const buildTable = () => { const headerLabels: Record = { - id: 'Process Instance Id', + id: 'Id', process_model_identifier: 'Process Model', start_in_seconds: 'Start Time', end_in_seconds: 'End Time', @@ -530,7 +530,9 @@ export default function ProcessInstanceListTable({ {headers.map((header: any) => ( - {header} + + {header} + ))} From c5b683ed2eabf52dcfb5a8c9a9b4eb7c54a1b089 Mon Sep 17 00:00:00 2001 From: burnettk Date: Thu, 17 Nov 2022 13:51:02 -0500 Subject: [PATCH 03/11] oops, just for one column --- .../src/components/ProcessInstanceListTable.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 5ce8dda1..a13fd016 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -530,7 +530,10 @@ export default function ProcessInstanceListTable({ {headers.map((header: any) => ( - + {header} ))} From 7c910e4ae43452e97605e4a7b60683ca17982ca7 Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 17 Nov 2022 15:03:11 -0500 Subject: [PATCH 04/11] attempting to use date objects as the date states w/ burnettk --- .../components/ProcessInstanceListTable.tsx | 126 ++++++++++-------- spiffworkflow-frontend/src/helpers.test.tsx | 4 +- spiffworkflow-frontend/src/helpers.tsx | 26 +++- .../src/routes/MessageInstanceList.tsx | 6 +- .../src/routes/ProcessInstanceLogList.tsx | 4 +- 5 files changed, 95 insertions(+), 71 deletions(-) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 407ac307..84c3fd62 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -27,8 +27,11 @@ import { } from '@carbon/react'; import { PROCESS_STATUSES, DATE_FORMAT, DATE_FORMAT_CARBON } from '../config'; import { + convertDateObjectToFormattedString, convertDateStringToSeconds, - convertSecondsToFormattedDate, + convertDateToSeconds, + convertSecondsToDateObject, + convertSecondsToFormattedDateString, convertSecondsToFormattedDateTime, getPageInfoFromSearchParams, getProcessModelFullIdentifierFromSearchParams, @@ -70,10 +73,13 @@ export default function ProcessInstanceListTable({ 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 [startFrom, setStartFrom] = useState( + null + ); + const [startTo, setStartTo] = useState(null); + const [startFromString, setStartFromString] = useState(''); + const [endFrom, setEndFrom] = useState(null); + const [endTo, setEndTo] = useState(null); const [showFilterOptions, setShowFilterOptions] = useState(false); const setErrorMessage = (useContext as any)(ErrorContext)[1]; @@ -140,10 +146,11 @@ export default function ProcessInstanceListTable({ const searchParamValue = searchParams.get(paramName); if (searchParamValue) { queryParamString += `&${paramName}=${searchParamValue}`; - const dateString = convertSecondsToFormattedDate( + const dateObject = convertSecondsToDateObject( searchParamValue as any ); - functionToCall(dateString); + console.log('dateObject1', dateObject); + functionToCall(dateObject); setShowFilterOptions(true); } }); @@ -160,6 +167,10 @@ export default function ProcessInstanceListTable({ const functionToCall = parametersToGetFromSearchParams[paramName]; queryParamString += `&${paramName}=${searchParams.get(paramName)}`; if (functionToCall !== null) { + console.log( + 'searchParams.get(paramName)', + searchParams.get(paramName) + ); functionToCall(searchParams.get(paramName) || ''); } setShowFilterOptions(true); @@ -223,45 +234,6 @@ export default function ProcessInstanceListTable({ perPageOptions, ]); - useEffect(() => { - const filters = processInstanceFilters as any; - Object.keys(parametersToAlwaysFilterBy).forEach((paramName: string) => { - // @ts-expect-error TS(7053) FIXME: - const functionToCall = parametersToAlwaysFilterBy[paramName]; - const paramValue = filters[paramName]; - functionToCall(''); - if (paramValue) { - const dateString = convertSecondsToFormattedDate(paramValue as any); - functionToCall(dateString); - setShowFilterOptions(true); - } - }); - - setProcessModelSelection(null); - processModelAvailableItems.forEach((item: any) => { - if (item.id === filters.process_model_identifier) { - setProcessModelSelection(item); - } - }); - - const processStatusSelectedArray: string[] = []; - if (filters.process_status) { - PROCESS_STATUSES.forEach((processStatusOption: any) => { - const regex = new RegExp(`\\b${processStatusOption}\\b`); - if (filters.process_status.match(regex)) { - processStatusSelectedArray.push(processStatusOption); - } - }); - setShowFilterOptions(true); - } - setProcessStatusSelection(processStatusSelectedArray); - }, [ - processInstanceFilters, - parametersToAlwaysFilterBy, - parametersToGetFromSearchParams, - processModelAvailableItems, - ]); - // 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) => { @@ -289,10 +261,10 @@ export default function ProcessInstanceListTable({ ); let queryParamString = `per_page=${perPage}&page=${page}&user_filter=true`; - const startFromSeconds = convertDateStringToSeconds(startFrom); - const endFromSeconds = convertDateStringToSeconds(endFrom); - const startToSeconds = convertDateStringToSeconds(startTo); - const endToSeconds = convertDateStringToSeconds(endTo); + const startFromSeconds = convertDateToSeconds(startFrom); + const endFromSeconds = convertDateToSeconds(endFrom); + const startToSeconds = convertDateToSeconds(startTo); + const endToSeconds = convertDateToSeconds(endTo); if (isTrueComparison(startFromSeconds, '>', startToSeconds)) { setErrorMessage({ message: '"Start date from" cannot be after "start date to"', @@ -346,8 +318,10 @@ export default function ProcessInstanceListTable({ labelString: any, name: any, initialDate: any, + initialDateString: string, onChangeFunction: any ) => { + // value={convertDateObjectToFormattedString(initialDate)} return ( <> @@ -360,9 +334,20 @@ export default function ProcessInstanceListTable({ autocomplete="off" allowInput={false} onChange={(dateChangeEvent: any) => { - onChangeFunction(dateChangeEvent.srcElement.value); + let dateTime = new Date(); + if (initialDate) { + dateTime = new Date(initialDate.getTime()); + } + + const [year, month, day] = + dateChangeEvent.srcElement.value.split('-'); + dateTime.setDate(day); + dateTime.setMonth(month - 1); + // @ts-ignore setYear does exist on Date + dateTime.setYear(year); + onChangeFunction(dateTime); }} - value={initialDate} + value={initialDateString} /> { setProcessModelSelection(null); setProcessStatusSelection([]); - setStartFrom(''); - setStartTo(''); - setEndFrom(''); - setEndTo(''); + setStartFrom(null); + setStartTo(null); + setEndFrom(null); + setEndTo(null); }; const filterOptions = () => { if (!showFilterOptions) { return null; } + console.log('startFrom', startFrom); return ( <> @@ -431,17 +417,36 @@ export default function ProcessInstanceListTable({ 'Start date from', 'start-from', startFrom, + startFromString, setStartFrom )} - {dateComponent('Start date to', 'start-to', startTo, setStartTo)} + {dateComponent( + 'Start date to', + 'start-to', + startTo, + startFromString, + setStartTo + )} - {dateComponent('End date from', 'end-from', endFrom, setEndFrom)} + {dateComponent( + 'End date from', + 'end-from', + endFrom, + startFromString, + setEndFrom + )} - {dateComponent('End date to', 'end-to', endTo, setEndTo)} + {dateComponent( + 'End date to', + 'end-to', + endTo, + startFromString, + setEndTo + )} @@ -587,6 +592,9 @@ export default function ProcessInstanceListTable({ }; if (pagination) { + setStartFromString( + convertDateObjectToFormattedString(startFrom as any) || '' + ); // eslint-disable-next-line prefer-const let { page, perPage } = getPageInfoFromSearchParams( searchParams, diff --git a/spiffworkflow-frontend/src/helpers.test.tsx b/spiffworkflow-frontend/src/helpers.test.tsx index 1031fc46..5a0352b8 100644 --- a/spiffworkflow-frontend/src/helpers.test.tsx +++ b/spiffworkflow-frontend/src/helpers.test.tsx @@ -1,4 +1,4 @@ -import { convertSecondsToFormattedDate, slugifyString } from './helpers'; +import { convertSecondsToFormattedDateString, slugifyString } from './helpers'; test('it can slugify a string', () => { expect(slugifyString('hello---world_ and then Some such-')).toEqual( @@ -7,6 +7,6 @@ test('it can slugify a string', () => { }); test('it can keep the correct date when converting seconds to date', () => { - const dateString = convertSecondsToFormattedDate(1666325400); + const dateString = convertSecondsToFormattedDateString(1666325400); expect(dateString).toEqual('2022-10-21'); }); diff --git a/spiffworkflow-frontend/src/helpers.tsx b/spiffworkflow-frontend/src/helpers.tsx index 37286c83..d163c00a 100644 --- a/spiffworkflow-frontend/src/helpers.tsx +++ b/spiffworkflow-frontend/src/helpers.tsx @@ -42,6 +42,13 @@ export const convertDateToSeconds = ( return null; }; +export const convertDateObjectToFormattedString = (dateObject: Date) => { + if (dateObject) { + return format(dateObject, DATE_FORMAT); + } + return null; +}; + export const convertStringToDate = (dateString: string) => { if (dateString) { // add midnight time to the date so it c uses the correct date @@ -51,18 +58,25 @@ export const convertStringToDate = (dateString: string) => { return null; }; -export const convertSecondsToFormattedDateTime = (seconds: number) => { +export const convertSecondsToDateObject = (seconds: number) => { if (seconds) { - const dateObject = new Date(seconds * 1000); + return new Date(seconds * 1000); + } + return null; +}; + +export const convertSecondsToFormattedDateTime = (seconds: number) => { + const dateObject = convertSecondsToDateObject(seconds); + if (dateObject) { return format(dateObject, DATE_TIME_FORMAT); } return null; }; -export const convertSecondsToFormattedDate = (seconds: number) => { - if (seconds) { - const dateObject = new Date(seconds * 1000); - return format(dateObject, DATE_FORMAT); +export const convertSecondsToFormattedDateString = (seconds: number) => { + const dateObject = convertSecondsToDateObject(seconds); + if (dateObject) { + return convertDateObjectToFormattedString(dateObject); } return null; }; diff --git a/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx b/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx index 09d28316..3ead5462 100644 --- a/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx +++ b/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx @@ -5,7 +5,7 @@ import { Link, useParams, useSearchParams } from 'react-router-dom'; import PaginationForTable from '../components/PaginationForTable'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import { - convertSecondsToFormattedDate, + convertSecondsToFormattedDateString, getPageInfoFromSearchParams, modifyProcessModelPath, unModifyProcessModelPath, @@ -68,7 +68,9 @@ export default function MessageInstanceList() { {rowToUse.failure_cause || '-'} {rowToUse.status} - {convertSecondsToFormattedDate(rowToUse.created_at_in_seconds)} + {convertSecondsToFormattedDateString( + rowToUse.created_at_in_seconds + )} ); diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx index 9f2d65b3..bb4468b4 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx @@ -6,7 +6,7 @@ import PaginationForTable from '../components/PaginationForTable'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import { getPageInfoFromSearchParams, - convertSecondsToFormattedDate, + convertSecondsToFormattedDateString, modifyProcessModelPath, unModifyProcessModelPath, } from '../helpers'; @@ -49,7 +49,7 @@ export default function ProcessInstanceLogList() { data-qa="process-instance-show-link" to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${rowToUse.process_instance_id}/${rowToUse.spiff_step}`} > - {convertSecondsToFormattedDate(rowToUse.timestamp)} + {convertSecondsToFormattedDateString(rowToUse.timestamp)} From 927f81ea07708e7cd43d86bdf40fdfa35a23f6ab Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 17 Nov 2022 16:05:54 -0500 Subject: [PATCH 05/11] times on instance list table are working now w/ burnettk --- .../components/ProcessInstanceListTable.tsx | 201 +++++++++++------- spiffworkflow-frontend/src/config.tsx | 1 + spiffworkflow-frontend/src/helpers.tsx | 47 +++- 3 files changed, 165 insertions(+), 84 deletions(-) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 84c3fd62..636481a4 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -21,18 +21,15 @@ import { TableHead, TableRow, TimePicker, - TimePickerSelect, - SelectItem, // @ts-ignore } from '@carbon/react'; import { PROCESS_STATUSES, DATE_FORMAT, DATE_FORMAT_CARBON } from '../config'; import { - convertDateObjectToFormattedString, - convertDateStringToSeconds, - convertDateToSeconds, - convertSecondsToDateObject, + convertDateAndTimeStringsToSeconds, + convertDateObjectToFormattedHoursMinutes, convertSecondsToFormattedDateString, convertSecondsToFormattedDateTime, + convertSecondsToFormattedTimeHoursMinutes, getPageInfoFromSearchParams, getProcessModelFullIdentifierFromSearchParams, modifyProcessModelPath, @@ -56,6 +53,10 @@ type OwnProps = { perPageOptions?: number[]; }; +interface dateParameters { + [key: string]: ((..._args: any[]) => any)[]; +} + export default function ProcessInstanceListTable({ filtersEnabled = true, processModelFullIdentifier, @@ -73,14 +74,20 @@ export default function ProcessInstanceListTable({ const oneHourInSeconds = 3600; const oneMonthInSeconds = oneHourInSeconds * 24 * 30; - const [startFrom, setStartFrom] = useState( - null - ); - const [startTo, setStartTo] = useState(null); - const [startFromString, setStartFromString] = useState(''); - const [endFrom, setEndFrom] = useState(null); - const [endTo, setEndTo] = useState(null); + const [startFromDate, setStartFromDate] = useState(''); + const [startToDate, setStartToDate] = useState(''); + const [endFromDate, setEndFromDate] = useState(''); + const [endToDate, setEndToDate] = useState(''); + const [startFromTime, setStartFromTime] = useState(''); + 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 setErrorMessage = (useContext as any)(ErrorContext)[1]; @@ -96,14 +103,23 @@ export default function ProcessInstanceListTable({ const [processModelSelection, setProcessModelSelection] = useState(null); - const parametersToAlwaysFilterBy = useMemo(() => { + const dateParametersToAlwaysFilterBy: dateParameters = useMemo(() => { return { - start_from: setStartFrom, - start_to: setStartTo, - end_from: setEndFrom, - end_to: setEndTo, + start_from: [setStartFromDate, setStartFromTime], + start_to: [setStartToDate, setStartToTime], + end_from: [setEndFromDate, setEndFromTime], + end_to: [setEndToDate, setEndToTime], }; - }, [setStartFrom, setStartTo, setEndFrom, setEndTo]); + }, [ + setStartFromDate, + setStartFromTime, + setStartToDate, + setStartToTime, + setEndFromDate, + setEndFromTime, + setEndToDate, + setEndToTime, + ]); const parametersToGetFromSearchParams = useMemo(() => { return { @@ -140,20 +156,27 @@ export default function ProcessInstanceListTable({ queryParamString += `&user_filter=${userAppliedFilter}`; } - 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 dateObject = convertSecondsToDateObject( - searchParamValue as any - ); - console.log('dateObject1', dateObject); - functionToCall(dateObject); - setShowFilterOptions(true); + Object.keys(dateParametersToAlwaysFilterBy).forEach( + (paramName: string) => { + const dateFunctionToCall = + dateParametersToAlwaysFilterBy[paramName][0]; + const timeFunctionToCall = + dateParametersToAlwaysFilterBy[paramName][1]; + const searchParamValue = searchParams.get(paramName); + if (searchParamValue) { + queryParamString += `&${paramName}=${searchParamValue}`; + const dateString = convertSecondsToFormattedDateString( + searchParamValue as any + ); + dateFunctionToCall(dateString); + const timeString = convertSecondsToFormattedTimeHoursMinutes( + searchParamValue as any + ); + timeFunctionToCall(timeString); + setShowFilterOptions(true); + } } - }); + ); Object.keys(parametersToGetFromSearchParams).forEach( (paramName: string) => { @@ -167,10 +190,6 @@ export default function ProcessInstanceListTable({ const functionToCall = parametersToGetFromSearchParams[paramName]; queryParamString += `&${paramName}=${searchParams.get(paramName)}`; if (functionToCall !== null) { - console.log( - 'searchParams.get(paramName)', - searchParams.get(paramName) - ); functionToCall(searchParams.get(paramName) || ''); } setShowFilterOptions(true); @@ -226,7 +245,7 @@ export default function ProcessInstanceListTable({ params, oneMonthInSeconds, oneHourInSeconds, - parametersToAlwaysFilterBy, + dateParametersToAlwaysFilterBy, parametersToGetFromSearchParams, filtersEnabled, paginationQueryParamPrefix, @@ -261,10 +280,22 @@ export default function ProcessInstanceListTable({ ); let queryParamString = `per_page=${perPage}&page=${page}&user_filter=true`; - const startFromSeconds = convertDateToSeconds(startFrom); - const endFromSeconds = convertDateToSeconds(endFrom); - const startToSeconds = convertDateToSeconds(startTo); - const endToSeconds = convertDateToSeconds(endTo); + const startFromSeconds = convertDateAndTimeStringsToSeconds( + startFromDate, + startFromTime + ); + const startToSeconds = convertDateAndTimeStringsToSeconds( + startToDate, + startToTime + ); + const endFromSeconds = convertDateAndTimeStringsToSeconds( + endFromDate, + endFromTime + ); + const endToSeconds = convertDateAndTimeStringsToSeconds( + endToDate, + endToTime + ); if (isTrueComparison(startFromSeconds, '>', startToSeconds)) { setErrorMessage({ message: '"Start date from" cannot be after "start date to"', @@ -318,10 +349,12 @@ export default function ProcessInstanceListTable({ labelString: any, name: any, initialDate: any, - initialDateString: string, - onChangeFunction: any + initialTime: string, + onChangeDateFunction: any, + onChangeTimeFunction: any, + timeInvalid: boolean, + setTimeInvalid: any ) => { - // value={convertDateObjectToFormattedString(initialDate)} return ( <> @@ -334,29 +367,29 @@ export default function ProcessInstanceListTable({ autocomplete="off" allowInput={false} onChange={(dateChangeEvent: any) => { - let dateTime = new Date(); - if (initialDate) { - dateTime = new Date(initialDate.getTime()); + if (!initialDate && !initialTime) { + onChangeTimeFunction( + convertDateObjectToFormattedHoursMinutes(new Date()) + ); } - - const [year, month, day] = - dateChangeEvent.srcElement.value.split('-'); - dateTime.setDate(day); - dateTime.setMonth(month - 1); - // @ts-ignore setYear does exist on Date - dateTime.setYear(year); - onChangeFunction(dateTime); + onChangeDateFunction(dateChangeEvent.srcElement.value); }} - value={initialDateString} + value={initialDate} /> { - console.log('event', event); + if (event.srcElement.validity.valid) { + setTimeInvalid(false); + } else { + setTimeInvalid(true); + } + onChangeTimeFunction(event.srcElement.value); }} /> @@ -386,17 +419,20 @@ export default function ProcessInstanceListTable({ const clearFilters = () => { setProcessModelSelection(null); setProcessStatusSelection([]); - setStartFrom(null); - setStartTo(null); - setEndFrom(null); - setEndTo(null); + setStartFromDate(''); + setStartFromTime(''); + setStartToDate(''); + setStartToTime(''); + setEndFromDate(''); + setEndFromTime(''); + setEndToDate(''); + setEndToTime(''); }; const filterOptions = () => { if (!showFilterOptions) { return null; } - console.log('startFrom', startFrom); return ( <> @@ -416,36 +452,48 @@ export default function ProcessInstanceListTable({ {dateComponent( 'Start date from', 'start-from', - startFrom, - startFromString, - setStartFrom + startFromDate, + startFromTime, + setStartFromDate, + setStartFromTime, + startFromTimeInvalid, + setStartFromTimeInvalid )} {dateComponent( 'Start date to', 'start-to', - startTo, - startFromString, - setStartTo + startToDate, + startToTime, + setStartToDate, + setStartToTime, + startToTimeInvalid, + setStartToTimeInvalid )} {dateComponent( 'End date from', 'end-from', - endFrom, - startFromString, - setEndFrom + endFromDate, + endFromTime, + setEndFromDate, + setEndFromTime, + endFromTimeInvalid, + setEndFromTimeInvalid )} {dateComponent( 'End date to', 'end-to', - endTo, - startFromString, - setEndTo + endToDate, + endToTime, + setEndToDate, + setEndToTime, + endToTimeInvalid, + setEndToTimeInvalid )} @@ -592,9 +640,6 @@ export default function ProcessInstanceListTable({ }; if (pagination) { - setStartFromString( - convertDateObjectToFormattedString(startFrom as any) || '' - ); // eslint-disable-next-line prefer-const let { page, perPage } = getPageInfoFromSearchParams( searchParams, diff --git a/spiffworkflow-frontend/src/config.tsx b/spiffworkflow-frontend/src/config.tsx index 47ff5025..5e7e96fe 100644 --- a/spiffworkflow-frontend/src/config.tsx +++ b/spiffworkflow-frontend/src/config.tsx @@ -18,5 +18,6 @@ export const PROCESS_STATUSES = [ // with time: yyyy-MM-dd HH:mm:ss export const DATE_TIME_FORMAT = 'yyyy-MM-dd HH:mm:ss'; +export const TIME_FORMAT_HOURS_MINUTES = 'HH:mm'; export const DATE_FORMAT = 'yyyy-MM-dd'; export const DATE_FORMAT_CARBON = 'Y-m-d'; diff --git a/spiffworkflow-frontend/src/helpers.tsx b/spiffworkflow-frontend/src/helpers.tsx index d163c00a..96478790 100644 --- a/spiffworkflow-frontend/src/helpers.tsx +++ b/spiffworkflow-frontend/src/helpers.tsx @@ -1,5 +1,9 @@ import { format } from 'date-fns'; -import { DATE_TIME_FORMAT, DATE_FORMAT } from './config'; +import { + DATE_TIME_FORMAT, + DATE_FORMAT, + TIME_FORMAT_HOURS_MINUTES, +} from './config'; import { DEFAULT_PER_PAGE, DEFAULT_PAGE, @@ -49,15 +53,31 @@ export const convertDateObjectToFormattedString = (dateObject: Date) => { return null; }; -export const convertStringToDate = (dateString: string) => { - if (dateString) { - // add midnight time to the date so it c uses the correct date - // after converting to timezone - return new Date(`${dateString}T00:10:00`); +export const convertDateAndTimeStringsToDate = ( + dateString: string, + timeString: string +) => { + if (dateString && timeString) { + return new Date(`${dateString}T${timeString}`); } return null; }; +export const convertDateAndTimeStringsToSeconds = ( + dateString: string, + timeString: string +) => { + const dateObject = convertDateAndTimeStringsToDate(dateString, timeString); + if (dateObject) { + return convertDateToSeconds(dateObject); + } + return null; +}; + +export const convertStringToDate = (dateString: string) => { + return convertDateAndTimeStringsToSeconds(dateString, '00:10:00'); +}; + export const convertSecondsToDateObject = (seconds: number) => { if (seconds) { return new Date(seconds * 1000); @@ -73,6 +93,21 @@ export const convertSecondsToFormattedDateTime = (seconds: number) => { return null; }; +export const convertDateObjectToFormattedHoursMinutes = (dateObject: Date) => { + if (dateObject) { + return format(dateObject, TIME_FORMAT_HOURS_MINUTES); + } + return null; +}; + +export const convertSecondsToFormattedTimeHoursMinutes = (seconds: number) => { + const dateObject = convertSecondsToDateObject(seconds); + if (dateObject) { + return convertDateObjectToFormattedHoursMinutes(dateObject); + } + return null; +}; + export const convertSecondsToFormattedDateString = (seconds: number) => { const dateObject = convertSecondsToDateObject(seconds); if (dateObject) { From 40b8a1c12ce2e265217251e4529532cf2b79b009 Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 17 Nov 2022 16:36:38 -0500 Subject: [PATCH 06/11] added back the useEffect for report filtering w/ burnettk --- .../components/ProcessInstanceListTable.tsx | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 636481a4..75de56c0 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -253,6 +253,54 @@ export default function ProcessInstanceListTable({ perPageOptions, ]); + // This sets the filter data using the saved reports returned from the initial instance_list query. + // This could probably be merged into the main useEffect but it works here now. + useEffect(() => { + const filters = processInstanceFilters as any; + Object.keys(dateParametersToAlwaysFilterBy).forEach((paramName: string) => { + const dateFunctionToCall = dateParametersToAlwaysFilterBy[paramName][0]; + const timeFunctionToCall = dateParametersToAlwaysFilterBy[paramName][1]; + const paramValue = filters[paramName]; + dateFunctionToCall(''); + timeFunctionToCall(''); + if (paramValue) { + const dateString = convertSecondsToFormattedDateString( + paramValue as any + ); + dateFunctionToCall(dateString); + const timeString = convertSecondsToFormattedTimeHoursMinutes( + paramValue as any + ); + timeFunctionToCall(timeString); + setShowFilterOptions(true); + } + }); + + setProcessModelSelection(null); + processModelAvailableItems.forEach((item: any) => { + if (item.id === filters.process_model_identifier) { + setProcessModelSelection(item); + } + }); + + const processStatusSelectedArray: string[] = []; + if (filters.process_status) { + PROCESS_STATUSES.forEach((processStatusOption: any) => { + const regex = new RegExp(`\\b${processStatusOption}\\b`); + if (filters.process_status.match(regex)) { + processStatusSelectedArray.push(processStatusOption); + } + }); + setShowFilterOptions(true); + } + setProcessStatusSelection(processStatusSelectedArray); + }, [ + processInstanceFilters, + dateParametersToAlwaysFilterBy, + parametersToGetFromSearchParams, + processModelAvailableItems, + ]); + // 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) => { From 08adf1758000bbcc25e5d2e13515c75d5b6a5d52 Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 17 Nov 2022 16:47:29 -0500 Subject: [PATCH 07/11] default time to midnight if it is null when filtering w/ burnettk --- .../src/components/ProcessInstanceListTable.tsx | 8 ++++---- .../src/routes/ProcessInstanceLogList.tsx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 163a2fc4..6d5fbb0b 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -330,19 +330,19 @@ export default function ProcessInstanceListTable({ const startFromSeconds = convertDateAndTimeStringsToSeconds( startFromDate, - startFromTime + startFromTime || '00:00:00' ); const startToSeconds = convertDateAndTimeStringsToSeconds( startToDate, - startToTime + startToTime || '00:00:00' ); const endFromSeconds = convertDateAndTimeStringsToSeconds( endFromDate, - endFromTime + endFromTime || '00:00:00' ); const endToSeconds = convertDateAndTimeStringsToSeconds( endToDate, - endToTime + endToTime || '00:00:00' ); if (isTrueComparison(startFromSeconds, '>', startToSeconds)) { setErrorMessage({ diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx index bb4468b4..214a0eac 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx @@ -6,9 +6,9 @@ import PaginationForTable from '../components/PaginationForTable'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import { getPageInfoFromSearchParams, - convertSecondsToFormattedDateString, modifyProcessModelPath, unModifyProcessModelPath, + convertSecondsToFormattedDateTime, } from '../helpers'; import HttpService from '../services/HttpService'; @@ -49,7 +49,7 @@ export default function ProcessInstanceLogList() { data-qa="process-instance-show-link" to={`/admin/process-models/${modifiedProcessModelId}/process-instances/${rowToUse.process_instance_id}/${rowToUse.spiff_step}`} > - {convertSecondsToFormattedDateString(rowToUse.timestamp)} + {convertSecondsToFormattedDateTime(rowToUse.timestamp)} From d3019ac6396d49f6842ebb8870f1d68d5139c37d Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 17 Nov 2022 17:30:51 -0500 Subject: [PATCH 08/11] hide messages and configuration if not authorized w/ burnettk --- .../src/components/NavigationBar.tsx | 71 +++++++++++++++---- .../src/hooks/UriListForPermissions.tsx | 2 + .../src/routes/Configuration.tsx | 29 ++++++-- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/spiffworkflow-frontend/src/components/NavigationBar.tsx b/spiffworkflow-frontend/src/components/NavigationBar.tsx index 6ef62ac8..0cc49158 100644 --- a/spiffworkflow-frontend/src/components/NavigationBar.tsx +++ b/spiffworkflow-frontend/src/components/NavigationBar.tsx @@ -17,9 +17,13 @@ import { import { Logout, Login } from '@carbon/icons-react'; import { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; +import { Can } from '@casl/react'; // @ts-expect-error TS(2307) FIXME: Cannot find module '../logo.svg' or its correspond... Remove this comment to see the full error message import logo from '../logo.svg'; import UserService from '../services/UserService'; +import { useUriListForPermissions } from '../hooks/UriListForPermissions'; +import { PermissionsToCheck } from '../interfaces'; +import { usePermissionFetcher } from '../hooks/PermissionService'; // for ref: https://react-bootstrap.github.io/components/navbar/ export default function NavigationBar() { @@ -34,6 +38,14 @@ export default function NavigationBar() { const location = useLocation(); const [activeKey, setActiveKey] = useState(''); + const { targetUris } = useUriListForPermissions(); + const permissionRequestData: PermissionsToCheck = { + [targetUris.authenticationListPath]: ['GET'], + [targetUris.messageInstanceListPath]: ['GET'], + [targetUris.secretListPath]: ['GET'], + }; + const { ability } = usePermissionFetcher(permissionRequestData); + useEffect(() => { let newActiveKey = '/admin/process-groups'; if (location.pathname.match(/^\/admin\/messages\b/)) { @@ -84,6 +96,42 @@ export default function NavigationBar() { ); }; + const configurationElement = () => { + return ( + + {(authenticationAllowed: boolean) => { + return ( + + {(secretAllowed: boolean) => { + if (secretAllowed || authenticationAllowed) { + return ( + + Configuration + + ); + } + return null; + }} + + ); + }} + + ); + }; + const headerMenuItems = () => { return ( <> @@ -103,18 +151,15 @@ export default function NavigationBar() { > Process Instances - - Messages - - - Configuration - + + + Messages + + + {configurationElement()} ( diff --git a/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx b/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx index c00cb286..9c61234b 100644 --- a/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx +++ b/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx @@ -3,6 +3,7 @@ import { useParams } from 'react-router-dom'; export const useUriListForPermissions = () => { const params = useParams(); const targetUris = { + authenticationListPath: `/v1.0/authentications`, messageInstanceListPath: '/v1.0/messages', processGroupListPath: '/v1.0/process-groups', processGroupShowPath: `/v1.0/process-groups/${params.process_group_id}`, @@ -12,6 +13,7 @@ export const useUriListForPermissions = () => { processModelFileCreatePath: `/v1.0/process-models/${params.process_model_id}/files`, processModelFileShowPath: `/v1.0/process-models/${params.process_model_id}/files/${params.file_name}`, processModelShowPath: `/v1.0/process-models/${params.process_model_id}`, + secretListPath: `/v1.0/secrets`, }; return { targetUris }; diff --git a/spiffworkflow-frontend/src/routes/Configuration.tsx b/spiffworkflow-frontend/src/routes/Configuration.tsx index 723a33ff..b2e30416 100644 --- a/spiffworkflow-frontend/src/routes/Configuration.tsx +++ b/spiffworkflow-frontend/src/routes/Configuration.tsx @@ -2,11 +2,15 @@ import { useContext, 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 SecretList from './SecretList'; import SecretNew from './SecretNew'; import SecretShow from './SecretShow'; import AuthenticationList from './AuthenticationList'; +import { useUriListForPermissions } from '../hooks/UriListForPermissions'; +import { PermissionsToCheck } from '../interfaces'; +import { usePermissionFetcher } from '../hooks/PermissionService'; export default function Configuration() { const location = useLocation(); @@ -14,6 +18,13 @@ export default function Configuration() { const [selectedTabIndex, setSelectedTabIndex] = useState(0); const navigate = useNavigate(); + const { targetUris } = useUriListForPermissions(); + const permissionRequestData: PermissionsToCheck = { + [targetUris.authenticationListPath]: ['GET'], + [targetUris.secretListPath]: ['GET'], + }; + const { ability } = usePermissionFetcher(permissionRequestData); + useEffect(() => { setErrorMessage(null); let newSelectedTabIndex = 0; @@ -27,12 +38,18 @@ export default function Configuration() { <> - navigate('/admin/configuration/secrets')}> - Secrets - - navigate('/admin/configuration/authentications')}> - Authentications - + + navigate('/admin/configuration/secrets')}> + Secrets + + + + navigate('/admin/configuration/authentications')} + > + Authentications + +
From 0c9e98260d2bb427a94f4557f2b83b802a9f44d3 Mon Sep 17 00:00:00 2001 From: burnettk Date: Thu, 17 Nov 2022 17:45:17 -0500 Subject: [PATCH 09/11] upgrades --- spiffworkflow-frontend/package-lock.json | 126 ++++++++--------------- 1 file changed, 43 insertions(+), 83 deletions(-) diff --git a/spiffworkflow-frontend/package-lock.json b/spiffworkflow-frontend/package-lock.json index 0dfe841a..f31017c8 100644 --- a/spiffworkflow-frontend/package-lock.json +++ b/spiffworkflow-frontend/package-lock.json @@ -19523,9 +19523,9 @@ } }, "node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -23895,9 +23895,9 @@ } }, "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", "engines": { "node": ">= 12.13.0" } @@ -24992,25 +24992,14 @@ } }, "node_modules/recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "dependencies": { - "minimatch": "3.0.4" + "minimatch": "^3.0.5" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "node": ">=6.0.0" } }, "node_modules/redent": { @@ -26064,9 +26053,9 @@ } }, "node_modules/serve": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/serve/-/serve-14.0.1.tgz", - "integrity": "sha512-tNGwxl27FwA8TbmMQqN0jTaSx8/trL532qZsJHX1VdiEIjjtMJHCs7AFS6OvtC7cTHOvmjXqt5yczejU6CV2Xg==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/serve/-/serve-14.1.1.tgz", + "integrity": "sha512-7RhRDEirZ7Qyee4QWhBHO9qRtjIGsIPGecDDPzNzlOsjDiZWcq36GS8FioVJAuJPVJBBDTsGp33WWOO4B9A82g==", "dependencies": { "@zeit/schemas": "2.21.0", "ajv": "8.11.0", @@ -26077,7 +26066,7 @@ "clipboardy": "3.0.0", "compression": "1.7.4", "is-port-reachable": "4.0.0", - "serve-handler": "6.1.3", + "serve-handler": "6.1.5", "update-check": "1.5.4" }, "bin": { @@ -26088,15 +26077,15 @@ } }, "node_modules/serve-handler": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", - "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", "fast-url-parser": "1.1.3", "mime-types": "2.1.18", - "minimatch": "3.0.4", + "minimatch": "3.1.2", "path-is-inside": "1.0.2", "path-to-regexp": "2.2.1", "range-parser": "1.2.0" @@ -26121,17 +26110,6 @@ "node": ">= 0.6" } }, - "node_modules/serve-handler/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -30691,9 +30669,9 @@ } }, "node_modules/webpack/node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -45923,9 +45901,9 @@ "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" }, "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -48920,9 +48898,9 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==" + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==" }, "supports-color": { "version": "7.2.0", @@ -49697,21 +49675,11 @@ } }, "recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "requires": { - "minimatch": "3.0.4" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } + "minimatch": "^3.0.5" } }, "redent": { @@ -50525,9 +50493,9 @@ } }, "serve": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/serve/-/serve-14.0.1.tgz", - "integrity": "sha512-tNGwxl27FwA8TbmMQqN0jTaSx8/trL532qZsJHX1VdiEIjjtMJHCs7AFS6OvtC7cTHOvmjXqt5yczejU6CV2Xg==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/serve/-/serve-14.1.1.tgz", + "integrity": "sha512-7RhRDEirZ7Qyee4QWhBHO9qRtjIGsIPGecDDPzNzlOsjDiZWcq36GS8FioVJAuJPVJBBDTsGp33WWOO4B9A82g==", "requires": { "@zeit/schemas": "2.21.0", "ajv": "8.11.0", @@ -50538,7 +50506,7 @@ "clipboardy": "3.0.0", "compression": "1.7.4", "is-port-reachable": "4.0.0", - "serve-handler": "6.1.3", + "serve-handler": "6.1.5", "update-check": "1.5.4" }, "dependencies": { @@ -50566,15 +50534,15 @@ } }, "serve-handler": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", - "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz", + "integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==", "requires": { "bytes": "3.0.0", "content-disposition": "0.5.2", "fast-url-parser": "1.1.3", "mime-types": "2.1.18", - "minimatch": "3.0.4", + "minimatch": "3.1.2", "path-is-inside": "1.0.2", "path-to-regexp": "2.2.1", "range-parser": "1.2.0" @@ -50592,14 +50560,6 @@ "requires": { "mime-db": "~1.33.0" } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } } } }, @@ -53954,9 +53914,9 @@ } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", From 349d91477c44a6d93d5dc02daee283b1232f04bd Mon Sep 17 00:00:00 2001 From: Elizabeth Esswein Date: Thu, 17 Nov 2022 22:52:26 -0500 Subject: [PATCH 10/11] add simple refresh capability --- spiffworkflow-frontend/src/helpers.tsx | 13 ++++++++ spiffworkflow-frontend/src/routes/MyTasks.tsx | 30 ++++++++++++------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/spiffworkflow-frontend/src/helpers.tsx b/spiffworkflow-frontend/src/helpers.tsx index 96478790..ab97c8dc 100644 --- a/spiffworkflow-frontend/src/helpers.tsx +++ b/spiffworkflow-frontend/src/helpers.tsx @@ -197,3 +197,16 @@ export const getGroupFromModifiedModelId = (modifiedId: string) => { export const splitProcessModelId = (processModelId: string) => { return processModelId.split('/'); }; + +export const refreshAtInterval = ( + interval: number, + timeout: number, + func: Function +) => { + const intervalRef = setInterval(() => func(), interval * 1000); + const timeoutRef = setTimeout( + () => clearInterval(intervalRef), + timeout * 1000 + ); + return [intervalRef, timeoutRef]; +}; diff --git a/spiffworkflow-frontend/src/routes/MyTasks.tsx b/spiffworkflow-frontend/src/routes/MyTasks.tsx index 010f3805..c59c49f5 100644 --- a/spiffworkflow-frontend/src/routes/MyTasks.tsx +++ b/spiffworkflow-frontend/src/routes/MyTasks.tsx @@ -6,11 +6,14 @@ import PaginationForTable from '../components/PaginationForTable'; import { getPageInfoFromSearchParams, modifyProcessModelPath, + refreshAtInterval, } from '../helpers'; import HttpService from '../services/HttpService'; import { PaginationObject, RecentProcessModel } from '../interfaces'; const PER_PAGE_FOR_TASKS_ON_HOME_PAGE = 5; +const REFRESH_INTERVAL = 10; +const REFRESH_TIMEOUT = 600; export default function MyTasks() { const [searchParams] = useSearchParams(); @@ -18,18 +21,23 @@ export default function MyTasks() { const [pagination, setPagination] = useState(null); useEffect(() => { - const { page, perPage } = getPageInfoFromSearchParams( - searchParams, - PER_PAGE_FOR_TASKS_ON_HOME_PAGE - ); - const setTasksFromResult = (result: any) => { - setTasks(result.results); - setPagination(result.pagination); + const getTasks = () => { + const { page, perPage } = getPageInfoFromSearchParams( + searchParams, + PER_PAGE_FOR_TASKS_ON_HOME_PAGE + ); + const setTasksFromResult = (result: any) => { + setTasks(result.results); + setPagination(result.pagination); + }; + HttpService.makeCallToBackend({ + path: `/tasks?per_page=${perPage}&page=${page}`, + successCallback: setTasksFromResult, + }); }; - HttpService.makeCallToBackend({ - path: `/tasks?per_page=${perPage}&page=${page}`, - successCallback: setTasksFromResult, - }); + + getTasks(); + refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks); }, [searchParams]); let recentProcessModels: RecentProcessModel[] = []; From dcf10eebeff05186d88e0533c85651770aad99db Mon Sep 17 00:00:00 2001 From: jbirddog <100367399+jbirddog@users.noreply.github.com> Date: Fri, 18 Nov 2022 07:40:36 -0500 Subject: [PATCH 11/11] Support reporting on task data (#47) --- .../routes/process_api_blueprint.py | 18 ++++++------------ .../services/process_instance_service.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py index a5b4c0aa..b3d5ec02 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -811,18 +811,12 @@ def process_instance_list( ProcessInstanceModel.start_in_seconds.desc(), ProcessInstanceModel.id.desc() # type: ignore ).paginate(page=page, per_page=per_page, error_out=False) - # TODO need to look into test failures when the results from result_dict is - # used instead of the process instances - - # substitution_variables = request.args.to_dict() - # result_dict = process_instance_report.generate_report( - # process_instances.items, substitution_variables - # ) - - # results = result_dict["results"] - # report_metadata = result_dict["report_metadata"] - - results = process_instances.items + results = list( + map( + ProcessInstanceService.serialize_flat_with_task_data, + process_instances.items, + ) + ) report_metadata = process_instance_report.report_metadata response_json = { diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py index aac9b176..244e6fb2 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py @@ -315,3 +315,22 @@ class ProcessInstanceService: ) return task + + @staticmethod + def serialize_flat_with_task_data( + process_instance: ProcessInstanceModel, + ) -> dict[str, Any]: + """serialize_flat_with_task_data.""" + results = {} + try: + original_status = process_instance.status + processor = ProcessInstanceProcessor(process_instance) + process_instance.data = processor.get_current_data() + results = process_instance.serialized_flat + # this process seems to mutate the status of the process_instance which + # can result in different results than expected from process_instance_list, + # so set the status back to the expected value + results["status"] = original_status + except ApiError: + results = process_instance.serialized + return results