diff --git a/awx/ui_next/src/api/models/WorkflowJobTemplates.js b/awx/ui_next/src/api/models/WorkflowJobTemplates.js index db84e26f7b..beed5be9ad 100644 --- a/awx/ui_next/src/api/models/WorkflowJobTemplates.js +++ b/awx/ui_next/src/api/models/WorkflowJobTemplates.js @@ -77,21 +77,28 @@ class WorkflowJobTemplates extends SchedulesMixin(NotificationsMixin(Base)) { readNotificationTemplatesApprovals(id, params) { return this.http.get( `${this.baseUrl}${id}/notification_templates_approvals/`, - { params } + { + params, + } ); } associateNotificationTemplatesApprovals(resourceId, notificationId) { return this.http.post( `${this.baseUrl}${resourceId}/notification_templates_approvals/`, - { id: notificationId } + { + id: notificationId, + } ); } disassociateNotificationTemplatesApprovals(resourceId, notificationId) { return this.http.post( `${this.baseUrl}${resourceId}/notification_templates_approvals/`, - { id: notificationId, disassociate: true } + { + id: notificationId, + disassociate: true, + } ); } } diff --git a/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx index f48e554317..c78bac17fb 100644 --- a/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx +++ b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.jsx @@ -1,15 +1,9 @@ import React, { useState, useRef, useEffect, Fragment } from 'react'; -import { Link } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import PropTypes from 'prop-types'; -import { - Dropdown, - DropdownPosition, - DropdownItem, -} from '@patternfly/react-core'; +import { Dropdown, DropdownPosition } from '@patternfly/react-core'; import { ToolbarAddButton } from '../PaginatedDataList'; -import { toTitleCase } from '../../util/strings'; import { useKebabifiedMenu } from '../../contexts/Kebabified'; function AddDropDownButton({ dropdownItems, i18n }) { @@ -31,15 +25,7 @@ function AddDropDownButton({ dropdownItems, i18n }) { }, [isKebabified]); if (isKebabified) { - return ( - - {dropdownItems.map(item => ( - - {toTitleCase(`${i18n._(t`Add`)} ${item.label}`)} - - ))} - - ); + return {dropdownItems}; } return ( @@ -50,31 +36,19 @@ function AddDropDownButton({ dropdownItems, i18n }) { position={DropdownPosition.right} toggle={ setIsOpen(!isOpen)} /> } - dropdownItems={dropdownItems.map(item => ( - - {item.label} - - ))} + dropdownItems={dropdownItems} /> ); } AddDropDownButton.propTypes = { - dropdownItems: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, - }) - ).isRequired, + dropdownItems: PropTypes.arrayOf(PropTypes.element.isRequired).isRequired, }; export { AddDropDownButton as _AddDropDownButton }; diff --git a/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx index 2c32607286..d1e16aaa22 100644 --- a/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx +++ b/awx/ui_next/src/components/AddDropDownButton/AddDropDownButton.test.jsx @@ -1,14 +1,12 @@ import React from 'react'; +import { DropdownItem } from '@patternfly/react-core'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; import AddDropDownButton from './AddDropDownButton'; describe('', () => { const dropdownItems = [ - { - key: 'inventory', - label: 'Inventory', - url: `inventory/inventory/add/`, - }, + Add, + Route, ]; test('should be closed initially', () => { const wrapper = mountWithContexts( @@ -23,7 +21,7 @@ describe('', () => { ); wrapper.find('button').simulate('click'); expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true); - expect(wrapper.find('Link')).toHaveLength(dropdownItems.length); + expect(wrapper.find('DropdownItem')).toHaveLength(dropdownItems.length); }); test('should close when button re-clicked', () => { diff --git a/awx/ui_next/src/components/DataListToolbar/DataListToolbar.test.jsx b/awx/ui_next/src/components/DataListToolbar/DataListToolbar.test.jsx index 6f90cc5d89..89d7966546 100644 --- a/awx/ui_next/src/components/DataListToolbar/DataListToolbar.test.jsx +++ b/awx/ui_next/src/components/DataListToolbar/DataListToolbar.test.jsx @@ -1,6 +1,8 @@ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; import DataListToolbar from './DataListToolbar'; +import AddDropDownButton from '../AddDropDownButton/AddDropDownButton'; describe('', () => { let toolbar; @@ -313,4 +315,44 @@ describe('', () => { search.prop('columns').filter(col => col.key === 'advanced').length ).toBe(1); }); + + test('should properly render toolbar buttons when in advanced search mode', async () => { + const searchColumns = [{ name: 'Name', key: 'name', isDefault: true }]; + const sortColumns = [{ name: 'Name', key: 'name' }]; + + const newToolbar = mountWithContexts( + + Add Contaner + , +
+ Add Instance Group +
, + ]} + />, + ]} + /> + ); + await act(() => + newToolbar.find('Search').prop('onShowAdvancedSearch')(true) + ); + newToolbar.update(); + expect(newToolbar.find('KebabToggle').length).toBe(1); + await act(() => newToolbar.find('KebabToggle').prop('onToggle')(true)); + newToolbar.update(); + expect(newToolbar.find('div[aria-label="add container"]').length).toBe(1); + expect(newToolbar.find('div[aria-label="add instance group"]').length).toBe( + 1 + ); + }); }); diff --git a/awx/ui_next/src/screens/Dashboard/shared/DashboardTemplateList.jsx b/awx/ui_next/src/screens/Dashboard/shared/DashboardTemplateList.jsx index 73c12cd0e2..c1fa638207 100644 --- a/awx/ui_next/src/screens/Dashboard/shared/DashboardTemplateList.jsx +++ b/awx/ui_next/src/screens/Dashboard/shared/DashboardTemplateList.jsx @@ -1,14 +1,15 @@ import React, { Fragment, useEffect, useState, useCallback } from 'react'; -import { useLocation } from 'react-router-dom'; +import { useLocation, Link } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { Card } from '@patternfly/react-core'; +import { Card, DropdownItem } from '@patternfly/react-core'; import { JobTemplatesAPI, UnifiedJobTemplatesAPI, WorkflowJobTemplatesAPI, } from '../../../api'; +import { toTitleCase } from '../../../util/strings'; import AlertModal from '../../../components/AlertModal'; import DatalistToolbar from '../../../components/DataListToolbar'; import ErrorDetail from '../../../components/ErrorDetail'; @@ -140,24 +141,31 @@ function DashboardTemplateList({ i18n }) { jtActions && Object.prototype.hasOwnProperty.call(jtActions, 'POST'); const canAddWFJT = wfjtActions && Object.prototype.hasOwnProperty.call(wfjtActions, 'POST'); - const addButtonOptions = []; - - if (canAddJT) { - addButtonOptions.push({ - label: i18n._(t`Job Template`), - url: `/templates/job_template/add/`, - }); - } - - if (canAddWFJT) { - addButtonOptions.push({ - label: i18n._(t`Workflow Template`), - url: `/templates/workflow_job_template/add/`, - }); - } + const addTempate = toTitleCase(i18n._(t`Add Job Template`)); + const addWFTemplate = toTitleCase(i18n._(t`Add Workflow Template`)); const addButton = ( - + + {addTempate} + , + + {addWFTemplate} + , + ]} + /> ); return ( diff --git a/awx/ui_next/src/screens/InstanceGroup/InstanceGroupList/InstanceGroupList.jsx b/awx/ui_next/src/screens/InstanceGroup/InstanceGroupList/InstanceGroupList.jsx index 794724ef6b..7b01510bed 100644 --- a/awx/ui_next/src/screens/InstanceGroup/InstanceGroupList/InstanceGroupList.jsx +++ b/awx/ui_next/src/screens/InstanceGroup/InstanceGroupList/InstanceGroupList.jsx @@ -1,13 +1,14 @@ import React, { useEffect, useCallback } from 'react'; -import { useLocation, useRouteMatch } from 'react-router-dom'; +import { useLocation, useRouteMatch, Link } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { Card, PageSection } from '@patternfly/react-core'; +import { Card, PageSection, DropdownItem } from '@patternfly/react-core'; import { InstanceGroupsAPI } from '../../../api'; import { getQSConfig, parseQueryString } from '../../../util/qs'; import useRequest, { useDeleteItems } from '../../../util/useRequest'; import useSelected from '../../../util/useSelected'; +import { toTitleCase } from '../../../util/strings'; import PaginatedDataList, { ToolbarDeleteButton, } from '../../../components/PaginatedDataList'; @@ -152,19 +153,31 @@ function InstanceGroupList({ i18n }) { ); } - const addButtonOptions = [ - { - label: i18n._(t`Instance group`), - url: '/instance_groups/add', - }, - { - label: i18n._(t`Container group`), - url: '/instance_groups/container_group/add', - }, - ]; + const addContainerGroup = toTitleCase(i18n._(t`Add Container Group`)); + const addInstanceGroup = toTitleCase(i18n._(t`Add Instance Group`)); const addButton = ( - + + {addContainerGroup} + , + + {addInstanceGroup} + , + ]} + /> ); const getDetailUrl = item => { diff --git a/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.jsx b/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.jsx index df1ebe2177..0b344ef1ce 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryGroupHosts/InventoryGroupHostList.jsx @@ -1,7 +1,8 @@ import React, { useEffect, useCallback, useState } from 'react'; -import { useHistory, useLocation, useParams } from 'react-router-dom'; +import { useLocation, useParams, Link } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; +import { DropdownItem } from '@patternfly/react-core'; import { getQSConfig, mergeParams, parseQueryString } from '../../../util/qs'; import { GroupsAPI, InventoriesAPI } from '../../../api'; @@ -18,7 +19,8 @@ import AssociateModal from '../../../components/AssociateModal'; import DisassociateButton from '../../../components/DisassociateButton'; import AdHocCommands from '../../../components/AdHocCommands/AdHocCommands'; import InventoryGroupHostListItem from './InventoryGroupHostListItem'; -import AddDropdown from '../shared/AddDropdown'; +import AddDropDownButton from '../../../components/AddDropDownButton'; +import { toTitleCase } from '../../../util/strings'; const QS_CONFIG = getQSConfig('host', { page: 1, @@ -30,7 +32,6 @@ function InventoryGroupHostList({ i18n }) { const [isModalOpen, setIsModalOpen] = useState(false); const { id: inventoryId, groupId } = useParams(); const location = useLocation(); - const history = useHistory(); const { result: { @@ -143,26 +144,31 @@ function InventoryGroupHostList({ i18n }) { const canAdd = actions && Object.prototype.hasOwnProperty.call(actions, 'POST'); const addFormUrl = `/inventories/inventory/${inventoryId}/groups/${groupId}/nested_hosts/add`; - const addButtonOptions = []; + const addExistingHost = toTitleCase(i18n._(t`Add Existing Host`)); + const addNewHost = toTitleCase(i18n._(t`Add New Host`)); - if (canAdd) { - addButtonOptions.push( - { - onAdd: () => setIsModalOpen(true), - title: i18n._(t`Add existing host`), - label: i18n._(t`host`), - key: 'existing', - }, - { - onAdd: () => history.push(addFormUrl), - title: i18n._(t`Add new host`), - label: i18n._(t`host`), - key: 'new', - } - ); - } - - const addButton = ; + const addButton = ( + setIsModalOpen(true)} + key={addExistingHost} + aria-label={addExistingHost} + > + {addExistingHost} + , + + {addNewHost} + , + ]} + /> + ); return ( <> ', () => { }); test('should show add dropdown button according to permissions', async () => { - expect(wrapper.find('AddDropdown').length).toBe(1); + expect(wrapper.find('AddDropDownButton').length).toBe(1); InventoriesAPI.readHostsOptions.mockResolvedValueOnce({ data: { actions: { @@ -109,7 +109,7 @@ describe('', () => { wrapper = mountWithContexts(); }); await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); - expect(wrapper.find('AddDropdown').length).toBe(0); + expect(wrapper.find('AddDropDownButton').length).toBe(0); }); test('expected api calls are made for multi-delete', async () => { @@ -156,9 +156,10 @@ describe('', () => { test('should show associate host modal when adding an existing host', () => { const dropdownToggle = wrapper.find( - 'DropdownToggle button[aria-label="add"]' + 'ToolbarAddButton button[aria-label="Add"]' ); dropdownToggle.simulate('click'); + wrapper .find('DropdownItem[aria-label="Add existing host"]') .simulate('click'); @@ -175,7 +176,7 @@ describe('', () => { results: [{ id: 123, name: 'foo', url: '/api/v2/hosts/123/' }], }, }); - wrapper.find('DropdownToggle button[aria-label="add"]').simulate('click'); + wrapper.find('ToolbarAddButton button[aria-label="Add"]').simulate('click'); await act(async () => { wrapper .find('DropdownItem[aria-label="Add existing host"]') @@ -205,7 +206,7 @@ describe('', () => { results: [{ id: 123, name: 'foo', url: '/api/v2/hosts/123/' }], }, }); - wrapper.find('DropdownToggle button[aria-label="add"]').simulate('click'); + wrapper.find('ToolbarAddButton[aria-label="Add"]').simulate('click'); await act(async () => { wrapper .find('DropdownItem[aria-label="Add existing host"]') @@ -240,7 +241,9 @@ describe('', () => { }, }, }); - const history = createMemoryHistory(); + const history = createMemoryHistory({ + initialEntries: ['/inventories/inventory/1/groups/2/nested_hosts/add'], + }); await act(async () => { wrapper = mountWithContexts(, { context: { @@ -250,10 +253,11 @@ describe('', () => { }); await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); const dropdownToggle = wrapper.find( - 'DropdownToggle button[aria-label="add"]' + 'ToolbarAddButton button[aria-label="Add"]' ); dropdownToggle.simulate('click'); wrapper.find('DropdownItem[aria-label="Add new host"]').simulate('click'); + wrapper.update(); expect(history.location.pathname).toEqual( '/inventories/inventory/1/groups/2/nested_hosts/add' ); diff --git a/awx/ui_next/src/screens/Inventory/InventoryGroups/InventoryGroupsList.test.jsx b/awx/ui_next/src/screens/Inventory/InventoryGroups/InventoryGroupsList.test.jsx index a0946a06fc..edc87e437d 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryGroups/InventoryGroupsList.test.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryGroups/InventoryGroupsList.test.jsx @@ -10,7 +10,12 @@ import { InventoriesAPI, GroupsAPI } from '../../../api'; import InventoryGroupsList from './InventoryGroupsList'; jest.mock('../../../api'); - +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: () => ({ + id: 1, + }), +})); const mockGroups = [ { id: 1, diff --git a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx index a386937b16..18e07cca82 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx @@ -1,10 +1,11 @@ import React, { useState, useCallback, useEffect } from 'react'; -import { useLocation, useRouteMatch } from 'react-router-dom'; +import { useLocation, useRouteMatch, Link } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { Card, PageSection } from '@patternfly/react-core'; +import { Card, PageSection, DropdownItem } from '@patternfly/react-core'; import { InventoriesAPI } from '../../../api'; import useRequest, { useDeleteItems } from '../../../util/useRequest'; +import { toTitleCase } from '../../../util/strings'; import AlertModal from '../../../components/AlertModal'; import DatalistToolbar from '../../../components/DataListToolbar'; import ErrorDetail from '../../../components/ErrorDetail'; @@ -124,19 +125,28 @@ function InventoryList({ i18n }) { } } }; - + const addInventory = toTitleCase(i18n._(t`Add Inventory`)); + const addSmartInventory = toTitleCase(i18n._(t`Add Smart Inventory`)); const addButton = ( + {addInventory} + , + + {addSmartInventory} + , ]} /> ); diff --git a/awx/ui_next/src/screens/Inventory/InventoryRelatedGroups/InventoryRelatedGroupList.jsx b/awx/ui_next/src/screens/Inventory/InventoryRelatedGroups/InventoryRelatedGroupList.jsx index eb171006c4..8e2e80790f 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryRelatedGroups/InventoryRelatedGroupList.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryRelatedGroups/InventoryRelatedGroupList.jsx @@ -1,8 +1,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { useParams, useLocation, useHistory } from 'react-router-dom'; +import { useParams, useLocation, Link } from 'react-router-dom'; +import { DropdownItem } from '@patternfly/react-core'; import { GroupsAPI, InventoriesAPI } from '../../../api'; import useRequest from '../../../util/useRequest'; import { getQSConfig, parseQueryString, mergeParams } from '../../../util/qs'; @@ -11,10 +12,11 @@ import useSelected from '../../../util/useSelected'; import DataListToolbar from '../../../components/DataListToolbar'; import PaginatedDataList from '../../../components/PaginatedDataList'; import InventoryGroupRelatedGroupListItem from './InventoryRelatedGroupListItem'; -import AddDropdown from '../shared/AddDropdown'; +import AddDropDownButton from '../../../components/AddDropDownButton'; import AdHocCommands from '../../../components/AdHocCommands/AdHocCommands'; import AssociateModal from '../../../components/AssociateModal'; import DisassociateButton from '../../../components/DisassociateButton'; +import { toTitleCase } from '../../../util/strings'; const QS_CONFIG = getQSConfig('group', { page: 1, @@ -25,7 +27,7 @@ function InventoryRelatedGroupList({ i18n }) { const [isModalOpen, setIsModalOpen] = useState(false); const { id: inventoryId, groupId } = useParams(); const location = useLocation(); - const history = useHistory(); + const { request: fetchRelated, result: { @@ -85,26 +87,31 @@ function InventoryRelatedGroupList({ i18n }) { ); const addFormUrl = `/home`; - const addButtonOptions = []; - if (canAdd) { - addButtonOptions.push( - { - onAdd: () => setIsModalOpen(true), - title: i18n._(t`Add existing group`), - label: i18n._(t`group`), - key: 'existing', - }, - { - onAdd: () => history.push(addFormUrl), - title: i18n._(t`Add new group`), - label: i18n._(t`group`), - key: 'new', - } - ); - } - - const addButton = ; + const addExistingGroup = toTitleCase(i18n._(t`Add Existing Group`)); + const addNewGroup = toTitleCase(i18n._(t`Add New Group`)); + const addButton = ( + setIsModalOpen(true)} + aria-label={addExistingGroup} + > + {addExistingGroup} + , + + {addNewGroup} + , + ]} + /> + ); return ( <> @@ -173,17 +180,7 @@ function InventoryRelatedGroupList({ i18n }) { onSelect={() => handleSelect(o)} /> )} - emptyStateControls={ - canAdd && ( - setIsModalOpen(true)} - onAddNew={() => history.push(addFormUrl)} - newTitle={i18n._(t`Add new group`)} - existingTitle={i18n._(t`Add existing group`)} - label={i18n._(t`group`)} - /> - ) - } + emptyStateControls={canAdd && addButton} /> {isModalOpen && ( { - const toggle = e => { - if (!isKebabified && (!element || !element.current.contains(e.target))) { - setIsOpen(false); - } - }; - - document.addEventListener('click', toggle, false); - return () => { - document.removeEventListener('click', toggle); - }; - }, [isKebabified]); - - if (isKebabified) { - return ( - - {dropdownItems.map(item => ( - - {item.title} - - ))} - - ); - } - - return ( -
- setIsOpen(prevState => !prevState)} - > - {i18n._(t`Add`)} - - } - dropdownItems={dropdownItems.map(item => ( - - {item.title} - - ))} - /> -
- ); -} - -AddDropdown.propTypes = { - dropdownItems: arrayOf( - shape({ - label: string.isRequired, - onAdd: func.isRequired, - key: string.isRequired, - }) - ).isRequired, -}; - -export { AddDropdown as _AddDropdown }; -export default withI18n()(AddDropdown); diff --git a/awx/ui_next/src/screens/Inventory/shared/AddDropdown.test.jsx b/awx/ui_next/src/screens/Inventory/shared/AddDropdown.test.jsx deleted file mode 100644 index 39b291bc8f..0000000000 --- a/awx/ui_next/src/screens/Inventory/shared/AddDropdown.test.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; -import AddDropdown from './AddDropdown'; - -describe('', () => { - let wrapper; - let dropdownToggle; - const dropdownItems = [ - { - onAdd: () => {}, - title: 'Add existing group', - label: 'group', - key: 'existing', - }, - { - onAdd: () => {}, - title: 'Add new group', - label: 'group', - key: 'new', - }, - ]; - - beforeEach(() => { - wrapper = mountWithContexts(); - dropdownToggle = wrapper.find('DropdownToggle button'); - }); - - test('should initially render a closed dropdown', () => { - expect(wrapper.find('DropdownItem').length).toBe(0); - }); - - test('should render two dropdown items', () => { - dropdownToggle.simulate('click'); - expect(wrapper.find('DropdownItem').length).toBe(2); - }); - - test('should close when button re-clicked', () => { - dropdownToggle.simulate('click'); - expect(wrapper.find('DropdownItem').length).toBe(2); - dropdownToggle.simulate('click'); - expect(wrapper.find('DropdownItem').length).toBe(0); - }); -}); diff --git a/awx/ui_next/src/screens/Template/TemplateList/TemplateList.jsx b/awx/ui_next/src/screens/Template/TemplateList/TemplateList.jsx index a40def657d..e88e6ce4db 100644 --- a/awx/ui_next/src/screens/Template/TemplateList/TemplateList.jsx +++ b/awx/ui_next/src/screens/Template/TemplateList/TemplateList.jsx @@ -1,9 +1,8 @@ import React, { Fragment, useEffect, useState, useCallback } from 'react'; -import { useLocation } from 'react-router-dom'; +import { useLocation, Link } from 'react-router-dom'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; -import { Card } from '@patternfly/react-core'; - +import { Card, DropdownItem } from '@patternfly/react-core'; import { JobTemplatesAPI, UnifiedJobTemplatesAPI, @@ -17,6 +16,7 @@ import PaginatedDataList, { } from '../../../components/PaginatedDataList'; import useRequest, { useDeleteItems } from '../../../util/useRequest'; import { getQSConfig, parseQueryString } from '../../../util/qs'; +import { toTitleCase } from '../../../util/strings'; import useWsTemplates from '../../../util/useWsTemplates'; import AddDropDownButton from '../../../components/AddDropDownButton'; import TemplateListItem from './TemplateListItem'; @@ -32,7 +32,6 @@ const QS_CONFIG = getQSConfig('template', { function TemplateList({ i18n }) { const location = useLocation(); - const [selected, setSelected] = useState([]); const { @@ -134,24 +133,36 @@ function TemplateList({ i18n }) { jtActions && Object.prototype.hasOwnProperty.call(jtActions, 'POST'); const canAddWFJT = wfjtActions && Object.prototype.hasOwnProperty.call(wfjtActions, 'POST'); - const addButtonOptions = []; + const addTempate = toTitleCase(i18n._(t`Add Job Template`)); + const addWFTemplate = toTitleCase(i18n._(t`Add Workflow Template`)); + const addDropDownButton = []; if (canAddJT) { - addButtonOptions.push({ - label: i18n._(t`Job Template`), - url: `/templates/job_template/add/`, - }); + addDropDownButton.push( + + {addTempate} + + ); } - if (canAddWFJT) { - addButtonOptions.push({ - label: i18n._(t`Workflow Template`), - url: `/templates/workflow_job_template/add/`, - }); + addDropDownButton.push( + + {addWFTemplate} + + ); } - const addButton = ( - + ); return (