convert HostList to PaginatedTable

This commit is contained in:
Keith Grant
2021-01-26 15:32:41 -08:00
parent 47de2ddcb5
commit f747edca0c
4 changed files with 92 additions and 101 deletions

View File

@@ -8,10 +8,14 @@ import { HostsAPI } from '../../../api';
import AlertModal from '../../../components/AlertModal'; import AlertModal from '../../../components/AlertModal';
import DataListToolbar from '../../../components/DataListToolbar'; import DataListToolbar from '../../../components/DataListToolbar';
import ErrorDetail from '../../../components/ErrorDetail'; import ErrorDetail from '../../../components/ErrorDetail';
import PaginatedDataList, { import {
ToolbarAddButton, ToolbarAddButton,
ToolbarDeleteButton, ToolbarDeleteButton,
} from '../../../components/PaginatedDataList'; } from '../../../components/PaginatedDataList';
import PaginatedTable, {
HeaderRow,
HeaderCell,
} from '../../../components/PaginatedTable';
import useRequest, { useDeleteItems } from '../../../util/useRequest'; import useRequest, { useDeleteItems } from '../../../util/useRequest';
import { import {
encodeQueryString, encodeQueryString,
@@ -130,7 +134,7 @@ function HostList({ i18n }) {
return ( return (
<PageSection> <PageSection>
<Card> <Card>
<PaginatedDataList <PaginatedTable
contentError={contentError} contentError={contentError}
hasContentLoading={isLoading || isDeleteLoading} hasContentLoading={isLoading || isDeleteLoading}
items={hosts} items={hosts}
@@ -157,14 +161,14 @@ function HostList({ i18n }) {
key: 'modified_by__username__icontains', key: 'modified_by__username__icontains',
}, },
]} ]}
toolbarSortColumns={[
{
name: i18n._(t`Name`),
key: 'name',
},
]}
toolbarSearchableKeys={searchableKeys} toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys} toolbarRelatedSearchableKeys={relatedSearchableKeys}
headerRow={
<HeaderRow qsConfig={QS_CONFIG}>
<HeaderCell sortKey="name">{i18n._(t`Name`)}</HeaderCell>
<HeaderCell>{i18n._(t`Inventory`)}</HeaderCell>
</HeaderRow>
}
renderToolbar={props => ( renderToolbar={props => (
<DataListToolbar <DataListToolbar
{...props} {...props}
@@ -193,13 +197,14 @@ function HostList({ i18n }) {
]} ]}
/> />
)} )}
renderItem={host => ( renderRow={(host, index) => (
<HostListItem <HostListItem
key={host.id} key={host.id}
host={host} host={host}
detailUrl={`${match.url}/${host.id}/details`} detailUrl={`${match.url}/${host.id}/details`}
isSelected={selected.some(row => row.id === host.id)} isSelected={selected.some(row => row.id === host.id)}
onSelect={() => handleSelect(host)} onSelect={() => handleSelect(host)}
rowIndex={index}
/> />
)} )}
emptyStateControls={ emptyStateControls={

View File

@@ -134,8 +134,9 @@ describe('<HostList />', () => {
act(() => { act(() => {
wrapper wrapper
.find('input#select-host-1') .find('.pf-c-table__check')
.closest('DataListCheck') .first()
.find('input')
.invoke('onChange')(); .invoke('onChange')();
}); });
wrapper.update(); wrapper.update();
@@ -147,8 +148,9 @@ describe('<HostList />', () => {
).toEqual(true); ).toEqual(true);
act(() => { act(() => {
wrapper wrapper
.find('input#select-host-1') .find('.pf-c-table__check')
.closest('DataListCheck') .first()
.find('input')
.invoke('onChange')(); .invoke('onChange')();
}); });
wrapper.update(); wrapper.update();

View File

@@ -1,76 +1,56 @@
import 'styled-components/macro'; import 'styled-components/macro';
import React, { Fragment } from 'react'; import React from 'react';
import { string, bool, func } from 'prop-types'; import { string, bool, func } from 'prop-types';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { import { Button } from '@patternfly/react-core';
Button, import { Tr, Td } from '@patternfly/react-table';
DataListAction as _DataListAction,
DataListCheck,
DataListItem,
DataListItemRow,
DataListItemCells,
Tooltip,
} from '@patternfly/react-core';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { PencilAltIcon } from '@patternfly/react-icons'; import { PencilAltIcon } from '@patternfly/react-icons';
import styled from 'styled-components'; import { ActionsTd, ActionItem } from '../../../components/PaginatedTable';
import DataListCell from '../../../components/DataListCell';
import Sparkline from '../../../components/Sparkline';
import { Host } from '../../../types'; import { Host } from '../../../types';
import HostToggle from '../../../components/HostToggle'; import HostToggle from '../../../components/HostToggle';
const DataListAction = styled(_DataListAction)` function HostListItem({
align-items: center; i18n,
display: grid; host,
grid-gap: 24px; isSelected,
grid-template-columns: 92px 40px; onSelect,
`; detailUrl,
rowIndex,
function HostListItem({ i18n, host, isSelected, onSelect, detailUrl }) { }) {
const labelId = `check-action-${host.id}`; const labelId = `check-action-${host.id}`;
return ( return (
<DataListItem key={host.id} aria-labelledby={labelId} id={`${host.id}`}> <Tr id={`host-row-${host.id}`}>
<DataListItemRow> <Td
<DataListCheck select={{
id={`select-host-${host.id}`} rowIndex,
checked={isSelected} isSelected,
onChange={onSelect} onSelect,
aria-labelledby={labelId} }}
dataLabel={i18n._(t`Selected`)}
/> />
<DataListItemCells <Td id={labelId} dataLabel={i18n._(t`Name`)}>
dataListCells={[
<DataListCell key="name">
<Link to={`${detailUrl}`}> <Link to={`${detailUrl}`}>
<b>{host.name}</b> <b>{host.name}</b>
</Link> </Link>
</DataListCell>, </Td>
<DataListCell key="recentJobs"> <Td dataLabel={i18n._(t`Inventory`)}>
<Sparkline jobs={host.summary_fields.recent_jobs} />
</DataListCell>,
<DataListCell key="inventory">
{host.summary_fields.inventory && ( {host.summary_fields.inventory && (
<Fragment>
<b css="margin-right: 24px">{i18n._(t`Inventory`)}</b>
<Link <Link
to={`/inventories/inventory/${host.summary_fields.inventory.id}/details`} to={`/inventories/inventory/${host.summary_fields.inventory.id}/details`}
> >
{host.summary_fields.inventory.name} {host.summary_fields.inventory.name}
</Link> </Link>
</Fragment>
)} )}
</DataListCell>, </Td>
]} <ActionsTd dataLabel={i18n._(t`Actions`)} gridColumns="auto 40px">
/>
<DataListAction
aria-label={i18n._(t`actions`)}
aria-labelledby={labelId}
id={labelId}
>
<HostToggle host={host} /> <HostToggle host={host} />
{host.summary_fields.user_capabilities.edit ? ( <ActionItem
<Tooltip content={i18n._(t`Edit Host`)} position="top"> visible={host.summary_fields.user_capabilities.edit}
tooltip={i18n._(t`Edit Host`)}
>
<Button <Button
aria-label={i18n._(t`Edit Host`)} aria-label={i18n._(t`Edit Host`)}
variant="plain" variant="plain"
@@ -79,13 +59,9 @@ function HostListItem({ i18n, host, isSelected, onSelect, detailUrl }) {
> >
<PencilAltIcon /> <PencilAltIcon />
</Button> </Button>
</Tooltip> </ActionItem>
) : ( </ActionsTd>
'' </Tr>
)}
</DataListAction>
</DataListItemRow>
</DataListItem>
); );
} }

View File

@@ -25,12 +25,16 @@ describe('<HostsListItem />', () => {
beforeEach(() => { beforeEach(() => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<table>
<tbody>
<HostsListItem <HostsListItem
isSelected={false} isSelected={false}
detailUrl="/host/1" detailUrl="/host/1"
onSelect={() => {}} onSelect={() => {}}
host={mockHost} host={mockHost}
/> />
</tbody>
</table>
); );
}); });
@@ -46,12 +50,16 @@ describe('<HostsListItem />', () => {
const copyMockHost = Object.assign({}, mockHost); const copyMockHost = Object.assign({}, mockHost);
copyMockHost.summary_fields.user_capabilities.edit = false; copyMockHost.summary_fields.user_capabilities.edit = false;
wrapper = mountWithContexts( wrapper = mountWithContexts(
<table>
<tbody>
<HostsListItem <HostsListItem
isSelected={false} isSelected={false}
detailUrl="/host/1" detailUrl="/host/1"
onSelect={() => {}} onSelect={() => {}}
host={copyMockHost} host={copyMockHost}
/> />
</tbody>
</table>
); );
expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy(); expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy();
}); });