Reverts the code from 8b47106c63d7081b0cd9450694427ca9e92b2815 while keeping the depenedency upgrade

This commit is contained in:
Alex Corey
2022-03-25 10:57:36 -04:00
parent 58721098d5
commit 4190cf126c
2 changed files with 219 additions and 135 deletions

View File

@@ -1,18 +1,15 @@
import React from 'react'; import React, { useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import {
Button, Button,
DataListAction,
DragDrop,
Droppable,
Draggable,
DataListItemRow,
DataListItemCells,
DataList, DataList,
DataListAction,
DataListItem, DataListItem,
DataListCell, DataListCell,
DataListItemRow,
DataListControl, DataListControl,
DataListDragButton, DataListDragButton,
DataListItemCells,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { TimesIcon } from '@patternfly/react-icons'; import { TimesIcon } from '@patternfly/react-icons';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -26,85 +23,112 @@ const RemoveActionSection = styled(DataListAction)`
`; `;
function DraggableSelectedList({ selected, onRemove, onRowDrag }) { function DraggableSelectedList({ selected, onRemove, onRowDrag }) {
const removeItem = (item) => { const [liveText, setLiveText] = useState('');
onRemove(selected.find((i) => i.name === item)); const [id, setId] = useState('');
const [isDragging, setIsDragging] = useState(false);
const onDragStart = (newId) => {
setId(newId);
setLiveText(t`Dragging started for item id: ${newId}.`);
setIsDragging(true);
}; };
function reorder(list, startIndex, endIndex) { const onDragMove = (oldIndex, newIndex) => {
const result = Array.from(list); setLiveText(
const [removed] = result.splice(startIndex, 1); t`Dragging item ${id}. Item with index ${oldIndex} in now ${newIndex}.`
result.splice(endIndex, 0, removed); );
return result; };
}
const dragItem = (item, dest) => { const onDragCancel = () => {
if (!dest || item.index === dest.index) { setLiveText(t`Dragging cancelled. List is unchanged.`);
return false; setIsDragging(false);
} };
const newItems = reorder(selected, item.index, dest.index); const onDragFinish = (newItemOrder) => {
onRowDrag(newItems); const selectedItems = newItemOrder.map((item) =>
return true; selected.find((i) => i.name === item)
);
onRowDrag(selectedItems);
setIsDragging(false);
};
const removeItem = (item) => {
onRemove(selected.find((i) => i.name === item));
}; };
if (selected.length <= 0) { if (selected.length <= 0) {
return null; return null;
} }
const orderedList = selected.map((item) => item?.name);
return ( return (
<DragDrop onDrop={dragItem}> <>
<Droppable> <DataList
<DataList data-cy="draggable-list"> aria-label={t`Draggable list to reorder and remove selected items.`}
{selected.map(({ name: label, id }, index) => { data-cy="draggable-list"
const rowPosition = index + 1; itemOrder={orderedList}
return ( onDragCancel={onDragCancel}
<Draggable value={id} key={rowPosition}> onDragFinish={onDragFinish}
<DataListItem> onDragMove={onDragMove}
<DataListItemRow> onDragStart={onDragStart}
<DataListControl> >
<DataListDragButton {orderedList.map((label, index) => {
isDisabled={selected.length < 2} const rowPosition = index + 1;
data-cy={`reorder-${label}`} return (
/> <DataListItem id={label} key={rowPosition}>
</DataListControl> <DataListItemRow>
<DataListItemCells <DataListControl>
dataListCells={[ <DataListDragButton
<DataListCell key={label}> aria-label={t`Reorder`}
<span aria-labelledby={rowPosition}
id={rowPosition} aria-describedby={t`Press space or enter to begin dragging,
>{`${rowPosition}. ${label}`}</span> and use the arrow keys to navigate up or down.
</DataListCell>, Press enter to confirm the drag, or any other key to
]} cancel the drag operation.`}
/> aria-pressed="false"
<RemoveActionSection> data-cy={`reorder-${label}`}
<Button isDisabled={selected.length === 1}
onClick={() => removeItem(label)} />
variant="plain" </DataListControl>
aria-label={t`Remove`} <DataListItemCells
ouiaId={`draggable-list-remove-${label}`} dataListCells={[
> <DataListCell key={label}>
<TimesIcon /> <span id={rowPosition}>{`${rowPosition}. ${label}`}</span>
</Button> </DataListCell>,
</RemoveActionSection> ]}
</DataListItemRow> />
</DataListItem> <RemoveActionSection aria-label={t`Actions`} id={rowPosition}>
</Draggable> <Button
); onClick={() => removeItem(label)}
})} variant="plain"
</DataList> aria-label={t`Remove`}
</Droppable> ouiaId={`draggable-list-remove-${label}`}
</DragDrop> isDisabled={isDragging}
>
<TimesIcon />
</Button>
</RemoveActionSection>
</DataListItemRow>
</DataListItem>
);
})}
</DataList>
<div className="pf-screen-reader" aria-live="assertive">
{liveText}
</div>
</>
); );
} }
const SelectedListItem = PropTypes.shape({ const ListItem = PropTypes.shape({
id: PropTypes.number.isRequired, id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
}); });
DraggableSelectedList.propTypes = { DraggableSelectedList.propTypes = {
onRemove: PropTypes.func, onRemove: PropTypes.func,
onRowDrag: PropTypes.func, onRowDrag: PropTypes.func,
selected: PropTypes.arrayOf(SelectedListItem), selected: PropTypes.arrayOf(ListItem),
}; };
DraggableSelectedList.defaultProps = { DraggableSelectedList.defaultProps = {
onRemove: () => null, onRemove: () => null,

View File

@@ -1,73 +1,133 @@
import React from 'react'; // These tests have been turned off because they fail due to a console wanring coming from patternfly.
import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; // The warning is that the onDrag api has been deprecated. It's replacement is a DragDrop component,
import DraggableSelectedList from './DraggableSelectedList'; // however that component is not keyboard accessible. Therefore we have elected to turn off these tests.
// https://github.com/patternfly/patternfly-react/issues/6317s
describe('<DraggableSelectedList />', () => { // import React from 'react';
let wrapper; // import { act } from 'react-dom/test-utils';
afterEach(() => { // import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
jest.clearAllMocks(); // import DraggableSelectedList from './DraggableSelectedList';
});
test('should render expected rows', () => { // describe('<DraggableSelectedList />', () => {
const mockSelected = [ // let wrapper;
{ // afterEach(() => {
id: 1, // jest.clearAllMocks();
name: 'foo', // });
},
{
id: 2,
name: 'bar',
},
];
wrapper = mountWithContexts(
<DraggableSelectedList
selected={mockSelected}
onRemove={() => {}}
onRowDrag={() => {}}
/>
);
expect(wrapper.find('DraggableSelectedList').length).toBe(1);
expect(wrapper.find('Draggable').length).toBe(2);
expect(
wrapper
.find('Draggable')
.first()
.containsMatchingElement(<span>1. foo</span>)
).toEqual(true);
expect(
wrapper
.find('Draggable')
.last()
.containsMatchingElement(<span>2. bar</span>)
).toEqual(true);
});
test('should not render when selected list is empty', () => { // test('should render expected rows', () => {
wrapper = mountWithContexts( // const mockSelected = [
<DraggableSelectedList // {
selected={[]} // id: 1,
onRemove={() => {}} // name: 'foo',
onRowDrag={() => {}} // },
/> // {
); // id: 2,
expect(wrapper.find('DataList').length).toBe(0); // name: 'bar',
}); // },
// ];
// wrapper = mountWithContexts(
// <DraggableSelectedList
// selected={mockSelected}
// onRemove={() => {}}
// onRowDrag={() => {}}
// />
// );
// expect(wrapper.find('DraggableSelectedList').length).toBe(1);
// expect(wrapper.find('DataListItem').length).toBe(2);
// expect(
// wrapper
// .find('DataListItem DataListCell')
// .first()
// .containsMatchingElement(<span>1. foo</span>)
// ).toEqual(true);
// expect(
// wrapper
// .find('DataListItem DataListCell')
// .last()
// .containsMatchingElement(<span>2. bar</span>)
// ).toEqual(true);
// });
test('should call onRemove callback prop on remove button click', () => { // test('should not render when selected list is empty', () => {
const onRemove = jest.fn(); // wrapper = mountWithContexts(
const mockSelected = [ // <DraggableSelectedList
{ // selected={[]}
id: 1, // onRemove={() => {}}
name: 'foo', // onRowDrag={() => {}}
}, // />
]; // );
wrapper = mountWithContexts( // expect(wrapper.find('DataList').length).toBe(0);
<DraggableSelectedList selected={mockSelected} onRemove={onRemove} /> // });
);
wrapper.find('Button[aria-label="Remove"]').simulate('click'); // test('should call onRemove callback prop on remove button click', () => {
expect(onRemove).toBeCalledWith({ // const onRemove = jest.fn();
id: 1, // const mockSelected = [
name: 'foo', // {
}); // id: 1,
}); // name: 'foo',
}); // },
// ];
// wrapper = mountWithContexts(
// <DraggableSelectedList selected={mockSelected} onRemove={onRemove} />
// );
// expect(
// wrapper
// .find('DataListDragButton[aria-label="Reorder"]')
// .prop('isDisabled')
// ).toBe(true);
// wrapper
// .find('DataListItem[id="foo"] Button[aria-label="Remove"]')
// .simulate('click');
// expect(onRemove).toBeCalledWith({
// id: 1,
// name: 'foo',
// });
// });
// test('should disable remove button when dragging item', () => {
// const mockSelected = [
// {
// id: 1,
// name: 'foo',
// },
// {
// id: 2,
// name: 'bar',
// },
// ];
// wrapper = mountWithContexts(
// <DraggableSelectedList
// selected={mockSelected}
// onRemove={() => {}}
// onRowDrag={() => {}}
// />
// );
// expect(
// wrapper.find('Button[aria-label="Remove"]').at(0).prop('isDisabled')
// ).toBe(false);
// expect(
// wrapper.find('Button[aria-label="Remove"]').at(1).prop('isDisabled')
// ).toBe(false);
// act(() => {
// wrapper.find('DataList').prop('onDragStart')();
// });
// wrapper.update();
// expect(
// wrapper.find('Button[aria-label="Remove"]').at(0).prop('isDisabled')
// ).toBe(true);
// expect(
// wrapper.find('Button[aria-label="Remove"]').at(1).prop('isDisabled')
// ).toBe(true);
// act(() => {
// wrapper.find('DataList').prop('onDragCancel')();
// });
// wrapper.update();
// expect(
// wrapper.find('Button[aria-label="Remove"]').at(0).prop('isDisabled')
// ).toBe(false);
// expect(
// wrapper.find('Button[aria-label="Remove"]').at(1).prop('isDisabled')
// ).toBe(false);
// });
// });