From 9bebcd8965dae6422a85448df8c1aecf57322f79 Mon Sep 17 00:00:00 2001 From: burnettk Date: Wed, 5 Oct 2022 13:03:35 -0400 Subject: [PATCH 1/5] process model search --- src/interfaces.ts | 7 +++ src/routes/HomePage.tsx | 1 - src/routes/ProcessGroupList.tsx | 75 ++++++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index 0f451f2..114f0ce 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -9,3 +9,10 @@ export interface RecentProcessModel { processModelIdentifier: string; processModelDisplayName: string; } + +export interface ProcessModel { + id: string; + process_group_id: string; + display_name: string; + primary_file_name: string; +} diff --git a/src/routes/HomePage.tsx b/src/routes/HomePage.tsx index 7a1acc6..38393f2 100644 --- a/src/routes/HomePage.tsx +++ b/src/routes/HomePage.tsx @@ -18,7 +18,6 @@ export default function HomePage() { searchParams, PER_PAGE_FOR_TASKS_ON_HOME_PAGE ); - console.log('perPageYo', perPage); const setTasksFromResult = (result: any) => { setTasks(result.results); setPagination(result.pagination); diff --git a/src/routes/ProcessGroupList.tsx b/src/routes/ProcessGroupList.tsx index 809d936..73b8f81 100644 --- a/src/routes/ProcessGroupList.tsx +++ b/src/routes/ProcessGroupList.tsx @@ -1,29 +1,50 @@ import { useEffect, useState } from 'react'; -import { Link, useSearchParams } from 'react-router-dom'; -import { Button, Table } from 'react-bootstrap'; +import { Link, useNavigate, useSearchParams } from 'react-router-dom'; +import { Button, Form, InputGroup, Table } from 'react-bootstrap'; +import { Typeahead } from 'react-bootstrap-typeahead'; +import { Option } from 'react-bootstrap-typeahead/types/types'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import PaginationForTable from '../components/PaginationForTable'; import HttpService from '../services/HttpService'; import { getPageInfoFromSearchParams } from '../helpers'; +import { ProcessModel } from '../interfaces'; // Example process group json -// {'admin': False, 'display_name': 'Test Workflows', 'display_order': 0, 'id': 'test_process_group'} +// {'process_group_id': 'sure', 'display_name': 'Test Workflows', 'id': 'test_process_group'} export default function ProcessGroupList() { + const navigate = useNavigate(); const [searchParams] = useSearchParams(); const [processGroups, setProcessGroups] = useState([]); const [pagination, setPagination] = useState(null); + const [processModeleSelectionOptions, setProcessModelSelectionOptions] = + useState([]); useEffect(() => { const setProcessGroupsFromResult = (result: any) => { setProcessGroups(result.results); setPagination(result.pagination); }; + const processResultForProcessModels = (result: any) => { + const selectionArray = result.results.map((item: any) => { + const label = `${item.process_group_id}/${item.id}`; + Object.assign(item, { label }); + return item; + }); + setProcessModelSelectionOptions(selectionArray); + }; + const { page, perPage } = getPageInfoFromSearchParams(searchParams); + // for browsing HttpService.makeCallToBackend({ path: `/process-groups?per_page=${perPage}&page=${page}`, successCallback: setProcessGroupsFromResult, }); + // for search box + HttpService.makeCallToBackend({ + path: `/process-models?per_page=1000`, + successCallback: processResultForProcessModels, + }); }, [searchParams]); const buildTable = () => { @@ -58,13 +79,16 @@ export default function ProcessGroupList() { let displayText = null; if (processGroups?.length > 0) { displayText = ( - + <> +

Browse

+ + ); } else { displayText =

No Groups To Display

; @@ -72,6 +96,35 @@ export default function ProcessGroupList() { return displayText; }; + const processModelSearchArea = () => { + const processModelSearchOnChange = (selected: Option[]) => { + const processModel = selected[0] as ProcessModel; + navigate( + `/admin/process-models/${processModel.process_group_id}/${processModel.id}` + ); + }; + return ( +
+

Search

+ + + + Process Model:{' '} + + + + +
+ ); + }; + if (pagination) { return ( <> @@ -79,6 +132,8 @@ export default function ProcessGroupList() {

+ {processModelSearchArea()} +
{processGroupsDisplayArea()} ); From 484e7e3d4b524852bfcf371c8383f5bcc0897682 Mon Sep 17 00:00:00 2001 From: burnettk Date: Wed, 5 Oct 2022 14:44:25 -0400 Subject: [PATCH 2/5] work in progress fixing tests --- cypress/e2e/process_groups.cy.js | 3 +-- cypress/e2e/process_instances.cy.js | 2 +- cypress/e2e/process_models.cy.js | 21 +++++++++++++++++---- cypress/support/commands.js | 21 ++++++++++++--------- src/routes/ProcessGroupList.tsx | 4 ++++ 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/cypress/e2e/process_groups.cy.js b/cypress/e2e/process_groups.cy.js index 1e61a8e..614d750 100644 --- a/cypress/e2e/process_groups.cy.js +++ b/cypress/e2e/process_groups.cy.js @@ -15,8 +15,7 @@ describe('process-groups', () => { cy.createGroup(groupId, groupDisplayName); cy.contains('Process Groups').click(); - cy.contains(groupId); - cy.contains(groupId).click(); + cy.contains(groupDisplayName).click(); cy.url().should('include', `process-groups/${groupId}`); cy.contains(`Process Group: ${groupId}`); diff --git a/cypress/e2e/process_instances.cy.js b/cypress/e2e/process_instances.cy.js index 26e98ad..1351ed1 100644 --- a/cypress/e2e/process_instances.cy.js +++ b/cypress/e2e/process_instances.cy.js @@ -58,7 +58,7 @@ describe('process-instances', () => { beforeEach(() => { cy.login(); cy.navigateToProcessModel( - 'acceptance-tests-group-one', + 'Acceptance Tests Group One', 'acceptance-tests-model-1' ); }); diff --git a/cypress/e2e/process_models.cy.js b/cypress/e2e/process_models.cy.js index a9d76b4..3b28514 100644 --- a/cypress/e2e/process_models.cy.js +++ b/cypress/e2e/process_models.cy.js @@ -10,10 +10,11 @@ describe('process-models', () => { const uuid = () => Cypress._.random(0, 1e6); const id = uuid(); const groupId = 'acceptance-tests-group-one'; + const groupDisplayName = 'Acceptance Tests Group One'; const modelDisplayName = `Test Model 2 ${id}`; const newModelDisplayName = `${modelDisplayName} edited`; const modelId = `test-model-2-${id}`; - cy.contains(groupId).click(); + cy.contains(groupDisplayName).click(); cy.createModel(groupId, modelId, modelDisplayName); cy.contains(`Process Group: ${groupId}`).click(); cy.contains(modelId); @@ -44,6 +45,7 @@ describe('process-models', () => { const uuid = () => Cypress._.random(0, 1e6); const id = uuid(); const groupId = 'acceptance-tests-group-one'; + const groupDisplayName = 'Acceptance Tests Group One'; const modelDisplayName = `Test Model 2 ${id}`; const modelId = `test-model-2-${id}`; @@ -51,7 +53,7 @@ describe('process-models', () => { const dmnFileName = `dmn_test_file_${id}`; const jsonFileName = `json_test_file_${id}`; - cy.contains(groupId).click(); + cy.contains(groupDisplayName).click(); cy.createModel(groupId, modelId, modelDisplayName); cy.contains(`Process Group: ${groupId}`).click(); cy.contains(modelId); @@ -119,10 +121,11 @@ describe('process-models', () => { const uuid = () => Cypress._.random(0, 1e6); const id = uuid(); const groupId = 'acceptance-tests-group-one'; + const groupDisplayName = 'Acceptance Tests Group One'; const modelDisplayName = `Test Model 2 ${id}`; const modelId = `test-model-2-${id}`; cy.contains('Add a process group'); - cy.contains(groupId).click(); + cy.contains(groupDisplayName).click(); cy.createModel(groupId, modelId, modelDisplayName); // seeing if getBySel works better, because we are seeing tests fail in CI @@ -160,7 +163,17 @@ describe('process-models', () => { }); it('can paginate items', () => { - cy.contains('acceptance-tests-group-one').click(); + cy.contains('Acceptance Tests Group One').click(); cy.basicPaginationTest(); }); + + it('can allow searching for model', () => { + cy.get('[name=process-model-selection]').click(); + cy.get('[name=process-model-selection]').type('model-3'); + cy.get( + `[aria-label="acceptance-tests-group-one/acceptance-tests-model-3"]` + ).click(); + + cy.contains('Process Instances').click(); + }); }); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 4e2c9fb..2510302 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -83,15 +83,18 @@ Cypress.Commands.add('runPrimaryBpmnFile', (reload = true) => { } }); -Cypress.Commands.add('navigateToProcessModel', (groupId, modelId) => { - cy.navigateToAdmin(); - cy.contains(groupId).click(); - cy.contains(`Process Group: ${groupId}`); - // https://stackoverflow.com/q/51254946/6090676 - cy.getBySel('process-model-show-link').contains(modelId).click(); - cy.url().should('include', `process-models/${groupId}/${modelId}`); - cy.contains(`Process Model: ${modelId}`); -}); +Cypress.Commands.add( + 'navigateToProcessModel', + (groupDisplayName, modelDisplayName) => { + cy.navigateToAdmin(); + cy.contains(groupDisplayName).click(); + cy.contains(`Process Group: ${groupDisplayName}`); + // https://stackoverflow.com/q/51254946/6090676 + cy.getBySel('process-model-show-link').contains(modelDisplayName).click(); + // cy.url().should('include', `process-models/${groupDisplayName}/${modelDisplayName}`); + cy.contains(`Process Model: ${modelDisplayName}`); + } +); Cypress.Commands.add('basicPaginationTest', () => { cy.get('#pagination-page-dropdown') diff --git a/src/routes/ProcessGroupList.tsx b/src/routes/ProcessGroupList.tsx index 73b8f81..37bddb4 100644 --- a/src/routes/ProcessGroupList.tsx +++ b/src/routes/ProcessGroupList.tsx @@ -116,6 +116,10 @@ export default function ProcessGroupList() { id="process-model-selection" labelKey="label" onChange={processModelSearchOnChange} + // for cypress tests since data-qa does not work + inputProps={{ + name: 'process-model-selection', + }} options={processModeleSelectionOptions} placeholder="Choose a process model..." /> From bd3be87ac91e01d4e475747988572354af466128 Mon Sep 17 00:00:00 2001 From: burnettk Date: Wed, 5 Oct 2022 15:29:19 -0400 Subject: [PATCH 3/5] fix cypress tests and support more generic hotCrumbs style in breadcrumb --- cypress/e2e/process_groups.cy.js | 4 ++-- cypress/e2e/tasks.cy.js | 10 +++++----- cypress/support/commands.js | 2 +- src/components/ProcessBreadcrumb.tsx | 26 +++++++++++++++++++++++++- src/interfaces.ts | 8 ++++++++ src/routes/ProcessGroupList.tsx | 2 +- src/routes/ProcessGroupShow.tsx | 17 ++++++++++++----- 7 files changed, 54 insertions(+), 15 deletions(-) diff --git a/cypress/e2e/process_groups.cy.js b/cypress/e2e/process_groups.cy.js index 614d750..1f2c675 100644 --- a/cypress/e2e/process_groups.cy.js +++ b/cypress/e2e/process_groups.cy.js @@ -17,12 +17,12 @@ describe('process-groups', () => { cy.contains('Process Groups').click(); cy.contains(groupDisplayName).click(); cy.url().should('include', `process-groups/${groupId}`); - cy.contains(`Process Group: ${groupId}`); + cy.contains(`Process Group: ${groupDisplayName}`); cy.contains('Edit process group').click(); cy.get('input[name=display_name]').clear().type(newGroupDisplayName); cy.contains('Submit').click(); - cy.contains(`Process Group: ${groupId}`); + cy.contains(`Process Group: ${newGroupDisplayName}`); cy.contains('Edit process group').click(); cy.get('input[name=display_name]').should( diff --git a/cypress/e2e/tasks.cy.js b/cypress/e2e/tasks.cy.js index 6c5a3ae..86298f5 100644 --- a/cypress/e2e/tasks.cy.js +++ b/cypress/e2e/tasks.cy.js @@ -22,12 +22,12 @@ describe('tasks', () => { }); it('can complete and navigate a form', () => { - const groupId = 'acceptance-tests-group-one'; + const groupDisplayName = 'Acceptance Tests Group One'; const modelId = `acceptance-tests-model-2`; const completedTaskClassName = 'completed-task-highlight'; const activeTaskClassName = 'active-task-highlight'; - cy.navigateToProcessModel(groupId, modelId); + cy.navigateToProcessModel(groupDisplayName, modelId); // avoid reloading so we can click on the task link that appears on running the process instance cy.runPrimaryBpmnFile(false); @@ -66,7 +66,7 @@ describe('tasks', () => { ); cy.contains('Task: get_user_generated_number_four'); - cy.navigateToProcessModel(groupId, modelId); + cy.navigateToProcessModel(groupDisplayName, modelId); cy.getBySel('process-instance-list-link').click(); cy.assertAtLeastOneItemInPaginatedResults(); @@ -98,7 +98,7 @@ describe('tasks', () => { ); cy.url().should('include', '/tasks'); - cy.navigateToProcessModel(groupId, modelId); + cy.navigateToProcessModel(groupDisplayName, modelId); cy.getBySel('process-instance-list-link').click(); cy.assertAtLeastOneItemInPaginatedResults(); @@ -110,7 +110,7 @@ describe('tasks', () => { it('can paginate items', () => { cy.navigateToProcessModel( - 'acceptance-tests-group-one', + 'Acceptance Tests Group One', 'acceptance-tests-model-2' ); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 2510302..5ea71d2 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -58,7 +58,7 @@ Cypress.Commands.add('createGroup', (groupId, groupDisplayName) => { cy.contains('Submit').click(); cy.url().should('include', `process-groups/${groupId}`); - cy.contains(`Process Group: ${groupId}`); + cy.contains(`Process Group: ${groupDisplayName}`); }); Cypress.Commands.add('createModel', (groupId, modelId, modelDisplayName) => { diff --git a/src/components/ProcessBreadcrumb.tsx b/src/components/ProcessBreadcrumb.tsx index b91f37c..4504f6e 100644 --- a/src/components/ProcessBreadcrumb.tsx +++ b/src/components/ProcessBreadcrumb.tsx @@ -1,20 +1,44 @@ import { Link } from 'react-router-dom'; import Breadcrumb from 'react-bootstrap/Breadcrumb'; +import { BreadcrumbItem } from '../interfaces'; type OwnProps = { processModelId?: string; processGroupId?: string; linkProcessModel?: boolean; + hotCrumbs?: BreadcrumbItem[]; }; export default function ProcessBreadcrumb({ processModelId, processGroupId, + hotCrumbs, linkProcessModel = false, }: OwnProps) { let processGroupBreadcrumb = null; let processModelBreadcrumb = null; - + if (hotCrumbs) { + const lastItem = hotCrumbs.pop(); + if (lastItem === undefined) { + return null; + } + const lastCrumb = {lastItem[0]}; + const leadingCrumbLinks = hotCrumbs.map((crumb) => { + const valueLabel = crumb[0]; + const url = crumb[1]; + return ( + + {valueLabel} + + ); + }); + return ( + + {leadingCrumbLinks} + {lastCrumb} + + ); + } if (processModelId) { if (linkProcessModel) { processModelBreadcrumb = ( diff --git a/src/interfaces.ts b/src/interfaces.ts index 114f0ce..2e023c9 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -10,9 +10,17 @@ export interface RecentProcessModel { processModelDisplayName: string; } +export interface ProcessGroup { + id: string; + display_name: string; +} + export interface ProcessModel { id: string; process_group_id: string; display_name: string; primary_file_name: string; } + +// tuple of display value and URL +export type BreadcrumbItem = [displayValue: string, url?: string]; diff --git a/src/routes/ProcessGroupList.tsx b/src/routes/ProcessGroupList.tsx index 37bddb4..3c1be15 100644 --- a/src/routes/ProcessGroupList.tsx +++ b/src/routes/ProcessGroupList.tsx @@ -132,7 +132,7 @@ export default function ProcessGroupList() { if (pagination) { return ( <> - +

diff --git a/src/routes/ProcessGroupShow.tsx b/src/routes/ProcessGroupShow.tsx index 89796af..522058c 100644 --- a/src/routes/ProcessGroupShow.tsx +++ b/src/routes/ProcessGroupShow.tsx @@ -5,12 +5,13 @@ import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import PaginationForTable from '../components/PaginationForTable'; import HttpService from '../services/HttpService'; import { getPageInfoFromSearchParams } from '../helpers'; +import { ProcessGroup } from '../interfaces'; export default function ProcessGroupShow() { const params = useParams(); const [searchParams] = useSearchParams(); - const [processGroup, setProcessGroup] = useState(null); + const [processGroup, setProcessGroup] = useState(null); const [processModels, setProcessModels] = useState([]); const [pagination, setPagination] = useState(null); @@ -35,14 +36,15 @@ export default function ProcessGroupShow() { }, [params, searchParams]); const buildTable = () => { + if (processGroup === null) { + return null; + } const rows = processModels.map((row) => { return ( {(row as any).id} @@ -72,7 +74,12 @@ export default function ProcessGroupShow() { const { page, perPage } = getPageInfoFromSearchParams(searchParams); return ( <> - +