Skip to content

Commit

Permalink
Reverts the code from 8b47106 while keeping the depenedency upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexSCorey committed Mar 25, 2022
1 parent e4c85a5 commit 1ce88df
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 70 deletions.
156 changes: 90 additions & 66 deletions awx/ui/src/components/SelectedList/DraggableSelectedList.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import React from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import {
Button,
DataListAction,
DragDrop,
Droppable,
Draggable,
DataListItemRow,
DataListItemCells,
DataList,
DataListAction,
DataListItem,
DataListCell,
DataListItemRow,
DataListControl,
DataListDragButton,
DataListItemCells,
} from '@patternfly/react-core';
import { TimesIcon } from '@patternfly/react-icons';
import styled from 'styled-components';
Expand All @@ -26,85 +23,112 @@ const RemoveActionSection = styled(DataListAction)`
`;

function DraggableSelectedList({ selected, onRemove, onRowDrag }) {
const removeItem = (item) => {
onRemove(selected.find((i) => i.name === item));
const [liveText, setLiveText] = useState('');
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 result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
}
const onDragMove = (oldIndex, newIndex) => {
setLiveText(
t`Dragging item ${id}. Item with index ${oldIndex} in now ${newIndex}.`
);
};

const onDragCancel = () => {
setLiveText(t`Dragging cancelled. List is unchanged.`);
setIsDragging(false);
};

const dragItem = (item, dest) => {
if (!dest || item.index === dest.index) {
return false;
}
const onDragFinish = (newItemOrder) => {
const selectedItems = newItemOrder.map((item) =>
selected.find((i) => i.name === item)
);
onRowDrag(selectedItems);
setIsDragging(false);
};

const newItems = reorder(selected, item.index, dest.index);
onRowDrag(newItems);
return true;
const removeItem = (item) => {
onRemove(selected.find((i) => i.name === item));
};

if (selected.length <= 0) {
return null;
}

const orderedList = selected.map((item) => item?.name);

return (
<DragDrop onDrop={dragItem}>
<Droppable>
<DataList data-cy="draggable-list">
{selected.map(({ name: label, id }, index) => {
const rowPosition = index + 1;
return (
<Draggable value={id} key={rowPosition}>
<DataListItem>
<DataListItemRow>
<DataListControl>
<DataListDragButton
isDisabled={selected.length < 2}
data-cy={`reorder-${label}`}
/>
</DataListControl>
<DataListItemCells
dataListCells={[
<DataListCell key={label}>
<span
id={rowPosition}
>{`${rowPosition}. ${label}`}</span>
</DataListCell>,
]}
/>
<RemoveActionSection>
<Button
onClick={() => removeItem(label)}
variant="plain"
aria-label={t`Remove`}
ouiaId={`draggable-list-remove-${label}`}
>
<TimesIcon />
</Button>
</RemoveActionSection>
</DataListItemRow>
</DataListItem>
</Draggable>
);
})}
</DataList>
</Droppable>
</DragDrop>
<>
<DataList
aria-label={t`Draggable list to reorder and remove selected items.`}
data-cy="draggable-list"
itemOrder={orderedList}
onDragCancel={onDragCancel}
onDragFinish={onDragFinish}
onDragMove={onDragMove}
onDragStart={onDragStart}
>
{orderedList.map((label, index) => {
const rowPosition = index + 1;
return (
<DataListItem id={label} key={rowPosition}>
<DataListItemRow>
<DataListControl>
<DataListDragButton
aria-label={t`Reorder`}
aria-labelledby={rowPosition}
aria-describedby={t`Press space or enter to begin dragging,
and use the arrow keys to navigate up or down.
Press enter to confirm the drag, or any other key to
cancel the drag operation.`}
aria-pressed="false"
data-cy={`reorder-${label}`}
isDisabled={selected.length === 1}
/>
</DataListControl>
<DataListItemCells
dataListCells={[
<DataListCell key={label}>
<span id={rowPosition}>{`${rowPosition}. ${label}`}</span>
</DataListCell>,
]}
/>
<RemoveActionSection aria-label={t`Actions`} id={rowPosition}>
<Button
onClick={() => removeItem(label)}
variant="plain"
aria-label={t`Remove`}
ouiaId={`draggable-list-remove-${label}`}
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,
name: PropTypes.string.isRequired,
});
DraggableSelectedList.propTypes = {
onRemove: PropTypes.func,
onRowDrag: PropTypes.func,
selected: PropTypes.arrayOf(SelectedListItem),
selected: PropTypes.arrayOf(ListItem),
};
DraggableSelectedList.defaultProps = {
onRemove: () => null,
Expand Down
63 changes: 59 additions & 4 deletions awx/ui/src/components/SelectedList/DraggableSelectedList.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import DraggableSelectedList from './DraggableSelectedList';

Expand Down Expand Up @@ -27,16 +28,16 @@ describe('<DraggableSelectedList />', () => {
/>
);
expect(wrapper.find('DraggableSelectedList').length).toBe(1);
expect(wrapper.find('Draggable').length).toBe(2);
expect(wrapper.find('DataListItem').length).toBe(2);
expect(
wrapper
.find('Draggable')
.find('DataListItem DataListCell')
.first()
.containsMatchingElement(<span>1. foo</span>)
).toEqual(true);
expect(
wrapper
.find('Draggable')
.find('DataListItem DataListCell')
.last()
.containsMatchingElement(<span>2. bar</span>)
).toEqual(true);
Expand Down Expand Up @@ -64,10 +65,64 @@ describe('<DraggableSelectedList />', () => {
wrapper = mountWithContexts(
<DraggableSelectedList selected={mockSelected} onRemove={onRemove} />
);
wrapper.find('Button[aria-label="Remove"]').simulate('click');
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);
});
});

0 comments on commit 1ce88df

Please sign in to comment.