From 87cf7971532a27f6cd6c8bce9c5f812240656955 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Fri, 29 Jan 2021 15:52:16 -0800 Subject: [PATCH] convert application list to tables --- .../ApplicationsList/ApplicationList.test.jsx | 32 +++-- .../ApplicationsList/ApplicationListItem.jsx | 125 ++++++------------ .../ApplicationListItem.test.jsx | 60 ++++----- .../ApplicationsList/ApplicationsList.jsx | 39 +++--- 4 files changed, 113 insertions(+), 143 deletions(-) diff --git a/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationList.test.jsx b/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationList.test.jsx index 7824ea5ed5..6832d07021 100644 --- a/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationList.test.jsx +++ b/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationList.test.jsx @@ -48,6 +48,7 @@ describe('', () => { }); await waitForElement(wrapper, 'ApplicationsList', el => el.length > 0); }); + test('should have data fetched and render 2 rows', async () => { ApplicationsAPI.read.mockResolvedValue(applications); ApplicationsAPI.readOptions.mockResolvedValue(options); @@ -69,14 +70,20 @@ describe('', () => { waitForElement(wrapper, 'ApplicationsList', el => el.length > 0); wrapper - .find('input#select-application-1') + .find('.pf-c-table__check') + .first() + .find('input') .simulate('change', applications.data.results[0]); wrapper.update(); - expect(wrapper.find('input#select-application-1').prop('checked')).toBe( - true - ); + expect( + wrapper + .find('.pf-c-table__check') + .first() + .find('input') + .prop('checked') + ).toBe(true); await act(async () => wrapper.find('Button[aria-label="Delete"]').prop('onClick')() ); @@ -131,13 +138,21 @@ describe('', () => { }); waitForElement(wrapper, 'ApplicationsList', el => el.length > 0); - wrapper.find('input#select-application-1').simulate('change', 'a'); + wrapper + .find('.pf-c-table__check') + .first() + .find('input') + .simulate('change', 'a'); wrapper.update(); - expect(wrapper.find('input#select-application-1').prop('checked')).toBe( - true - ); + expect( + wrapper + .find('.pf-c-table__check') + .first() + .find('input') + .prop('checked') + ).toBe(true); await act(async () => wrapper.find('Button[aria-label="Delete"]').prop('onClick')() ); @@ -163,6 +178,7 @@ describe('', () => { waitForElement(wrapper, 'ApplicationsList', el => el.length > 0); expect(wrapper.find('ToolbarAddButton').length).toBe(0); }); + test('should not render edit button for first list item', async () => { applications.data.results[0].summary_fields.user_capabilities.edit = false; ApplicationsAPI.read.mockResolvedValue(applications); diff --git a/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationListItem.jsx b/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationListItem.jsx index 1a0f5c9f4e..0d8a10b98e 100644 --- a/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationListItem.jsx +++ b/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationListItem.jsx @@ -1,104 +1,65 @@ import React from 'react'; import { string, bool, func } from 'prop-types'; import { withI18n } from '@lingui/react'; -import { - Button, - DataListAction as _DataListAction, - DataListCheck, - DataListItem, - DataListItemCells, - DataListItemRow, - Tooltip, -} from '@patternfly/react-core'; - +import { Button } from '@patternfly/react-core'; +import { Tr, Td } from '@patternfly/react-table'; import { t } from '@lingui/macro'; import { Link } from 'react-router-dom'; -import styled from 'styled-components'; import { PencilAltIcon } from '@patternfly/react-icons'; +import { ActionsTd, ActionItem } from '../../../components/PaginatedTable'; import { formatDateString } from '../../../util/dates'; import { Application } from '../../../types'; -import DataListCell from '../../../components/DataListCell'; - -const DataListAction = styled(_DataListAction)` - align-items: center; - display: grid; - grid-gap: 16px; - grid-template-columns: 40px; -`; - -const Label = styled.b` - margin-right: 20px; -`; function ApplicationListItem({ application, isSelected, onSelect, detailUrl, + rowIndex, i18n, }) { const labelId = `check-action-${application.id}`; return ( - - - - - - {application.name} - - , - - - {application.summary_fields.organization.name} - - , - - - {formatDateString(application.modified)} - , - ]} - /> - + + + + {application.name} + + + + - {application.summary_fields.user_capabilities.edit ? ( - - - - ) : ( - '' - )} - - - + {application.summary_fields.organization.name} + + + + {formatDateString(application.modified)} + + + + + + + ); } diff --git a/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationListItem.test.jsx b/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationListItem.test.jsx index 0a53dd4cd8..510c89ff28 100644 --- a/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationListItem.test.jsx +++ b/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationListItem.test.jsx @@ -18,12 +18,16 @@ describe('', () => { test('should mount successfully', async () => { await act(async () => { wrapper = mountWithContexts( - {}} - /> + + + {}} + /> + +
); }); expect(wrapper.find('ApplicationListItem').length).toBe(1); @@ -31,38 +35,30 @@ describe('', () => { test('should render the proper data', async () => { await act(async () => { wrapper = mountWithContexts( - {}} - /> + + + {}} + /> + +
); }); expect( - wrapper.find('DataListCell[aria-label="application name"]').text() + wrapper + .find('Td') + .at(1) + .text() ).toBe('Foo'); expect( - wrapper.find('DataListCell[aria-label="organization name"]').text() + wrapper + .find('Td') + .at(2) + .text() ).toBe('Organization'); - expect(wrapper.find('input#select-application-1').prop('checked')).toBe( - false - ); expect(wrapper.find('PencilAltIcon').length).toBe(1); }); - test('should be checked', async () => { - await act(async () => { - wrapper = mountWithContexts( - {}} - /> - ); - }); - expect(wrapper.find('input#select-application-1').prop('checked')).toBe( - true - ); - }); }); diff --git a/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationsList.jsx b/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationsList.jsx index b35ecc7d68..5ed5e092da 100644 --- a/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationsList.jsx +++ b/awx/ui_next/src/screens/Application/ApplicationsList/ApplicationsList.jsx @@ -11,7 +11,11 @@ import AlertModal from '../../../components/AlertModal'; import DatalistToolbar from '../../../components/DataListToolbar'; import { ApplicationsAPI } from '../../../api'; -import PaginatedDataList, { +import PaginatedTable, { + HeaderRow, + HeaderCell, +} from '../../../components/PaginatedTable'; +import { ToolbarDeleteButton, ToolbarAddButton, } from '../../../components/PaginatedDataList'; @@ -104,7 +108,7 @@ function ApplicationsList({ i18n }) { <> - ( @@ -170,7 +156,17 @@ function ApplicationsList({ i18n }) { ]} /> )} - renderItem={application => ( + headerRow={ + + {i18n._(t`Name`)} + + {i18n._(t`Organization`)} + + {i18n._(t`Last Modified`)} + {i18n._(t`Actions`)} + + } + renderRow={(application, index) => ( handleSelect(application)} isSelected={selected.some(row => row.id === application.id)} + rowIndex={index} /> )} emptyStateControls={