From ce8897d3e82580f344a85cf69f28a6da045d50a0 Mon Sep 17 00:00:00 2001 From: Alex Corey Date: Sun, 23 Feb 2020 11:16:44 -0500 Subject: [PATCH] Fixes naviation bug by create ProjectTemplateList and ProjectTemplateListItem Adds tests for those new files and removes uncessary test from TemplateListItem --- .../ProjectJobTemplatesList.jsx | 4 +- .../ProjectJobTemplatesListItem.jsx | 126 ++++++++++++ .../ProjectJobTemplatesListItem.test.jsx | 189 ++++++++++++++++++ .../TemplateList/TemplateListItem.jsx | 8 +- .../TemplateList/TemplateListItem.test.jsx | 84 ++------ 5 files changed, 330 insertions(+), 81 deletions(-) create mode 100644 awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesListItem.jsx create mode 100644 awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesListItem.test.jsx diff --git a/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesList.jsx b/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesList.jsx index 5f36cd7938..bec336f4e6 100644 --- a/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesList.jsx +++ b/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesList.jsx @@ -18,7 +18,7 @@ import PaginatedDataList, { import { getQSConfig, parseQueryString } from '@util/qs'; import AddDropDownButton from '@components/AddDropDownButton'; -import ProjectTemplatesListItem from '../../Template/TemplateList/TemplateListItem'; +import ProjectTemplatesListItem from './ProjectJobTemplatesListItem'; // The type value in const QS_CONFIG below does not have a space between job_template and // workflow_job_template so the params sent to the API match what the api expects. @@ -238,7 +238,7 @@ function ProjectJobTemplatesList({ i18n }) { itemsToDelete={selected} pluralizedItemName="Templates" />, - (canAddJT || canAddWFJT) && addButton, + ...(canAddJT || canAddWFJT ? [addButton] : []), ]} /> )} diff --git a/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesListItem.jsx b/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesListItem.jsx new file mode 100644 index 0000000000..ea46bb967b --- /dev/null +++ b/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesListItem.jsx @@ -0,0 +1,126 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { + Button, + DataListAction as _DataListAction, + DataListCell, + DataListCheck, + DataListItem, + DataListItemRow, + DataListItemCells, + Tooltip, +} from '@patternfly/react-core'; +import { t } from '@lingui/macro'; +import { withI18n } from '@lingui/react'; +import { + ExclamationTriangleIcon, + PencilAltIcon, + RocketIcon, +} from '@patternfly/react-icons'; + +import LaunchButton from '@components/LaunchButton'; +import Sparkline from '@components/Sparkline'; +import { toTitleCase } from '@util/strings'; +import styled from 'styled-components'; + +const DataListAction = styled(_DataListAction)` + align-items: center; + display: grid; + grid-gap: 16px; + grid-template-columns: repeat(2, 40px); +`; + +function ProjectJobTemplateListItem({ + i18n, + template, + isSelected, + onSelect, + detailUrl, +}) { + const labelId = `check-action-${template.id}`; + const canLaunch = template.summary_fields.user_capabilities.start; + + const missingResourceIcon = + template.type === 'job_template' && + (!template.summary_fields.project || + (!template.summary_fields.inventory && + !template.ask_inventory_on_launch)); + + return ( + + + + + + + {template.name} + + + {missingResourceIcon && ( + + + + + + )} + , + + {toTitleCase(template.type)} + , + + + , + ]} + /> + + {canLaunch && template.type === 'job_template' && ( + + + {({ handleLaunch }) => ( + + )} + + + )} + {template.summary_fields.user_capabilities.edit && ( + + + + )} + + + + ); +} + +export { ProjectJobTemplateListItem as _ProjectJobTemplateListItem }; +export default withI18n()(ProjectJobTemplateListItem); diff --git a/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesListItem.test.jsx b/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesListItem.test.jsx new file mode 100644 index 0000000000..f94fc1a6e2 --- /dev/null +++ b/awx/ui_next/src/screens/Project/ProjectJobTemplatesList/ProjectJobTemplatesListItem.test.jsx @@ -0,0 +1,189 @@ +import React from 'react'; + +import { mountWithContexts } from '@testUtils/enzymeHelpers'; +import { createMemoryHistory } from 'history'; +import ProjectJobTemplatesListItem from './ProjectJobTemplatesListItem'; + +describe('', () => { + test('launch button shown to users with start capabilities', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('LaunchButton').exists()).toBeTruthy(); + }); + test('launch button hidden from users without start capabilities', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('LaunchButton').exists()).toBeFalsy(); + }); + test('edit button shown to users with edit capabilities', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('PencilAltIcon').exists()).toBeTruthy(); + }); + test('edit button hidden from users without edit capabilities', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy(); + }); + test('missing resource icon is shown.', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(true); + }); + test('missing resource icon is not shown when there is a project and an inventory.', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(false); + }); + test('missing resource icon is not shown when inventory is prompt_on_launch, and a project', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(false); + }); + test('missing resource icon is not shown type is workflow_job_template', () => { + const wrapper = mountWithContexts( + + ); + expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(false); + }); + test('clicking on template from project templates list navigates properly', () => { + const history = createMemoryHistory({ + initialEntries: ['/projects/1/job_templates'], + }); + const wrapper = mountWithContexts( + , + { context: { router: { history } } } + ); + wrapper.find('Link').simulate('click', { button: 0 }); + expect(history.location.pathname).toEqual( + '/templates/job_template/2/details' + ); + }); +}); diff --git a/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.jsx b/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.jsx index 86c506912e..b13eb92298 100644 --- a/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.jsx +++ b/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Link, useLocation } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import { Button, DataListAction as _DataListAction, @@ -40,12 +40,6 @@ function TemplateListItem({ i18n, template, isSelected, onSelect, detailUrl }) { (!template.summary_fields.inventory && !template.ask_inventory_on_launch)); - // const location = useLocation(); - - // if (location.pathname.startsWith('/projects')) { - // detailUrl = `/templates/job_template/${template.id}/details`; - // } - return ( diff --git a/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.test.jsx b/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.test.jsx index d834478668..df84a79cec 100644 --- a/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.test.jsx +++ b/awx/ui_next/src/screens/Template/TemplateList/TemplateListItem.test.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Route } from 'react-router-dom'; import { mountWithContexts } from '@testUtils/enzymeHelpers'; import { createMemoryHistory } from 'history'; @@ -167,83 +166,24 @@ describe('', () => { initialEntries: ['/templates'], }); const wrapper = mountWithContexts( - ( - - )} - />, - { - context: { - router: { - history, - route: { - location: history.location, - match: { - params: { id: 1 }, - }, + , + { context: { router: { history } } } ); wrapper.find('Link').simulate('click', { button: 0 }); expect(history.location.pathname).toEqual( '/templates/job_template/1/details' ); }); - test('clicking on template from project templates list navigates properly', () => { - const history = createMemoryHistory({ - initialEntries: ['/projects/1/job_templates'], - }); - const wrapper = mountWithContexts( - ( - - )} - />, - { - context: { - router: { - history, - route: { - location: history.location, - match: { - params: { id: 1 }, - }, - }, - }, - }, - } - ); - wrapper.find('Link').simulate('click', { button: 0 }); - expect(history.location.pathname).toEqual( - '/templates/job_template/2/details' - ); - }); });