Skip to content

Commit bcc58ac

Browse files
author
Konstantinos Familonidis
committed
Refs #38822: update pf3 buttons to pf5 - common/ActionButtons
Upgrade ActionButtons and replace Enzyme tests with RTL. Fix styling an replace bgStyle with equivalent variant props.
1 parent 45f7dfd commit bcc58ac

File tree

5 files changed

+118
-75
lines changed

5 files changed

+118
-75
lines changed
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { noop } from '../../../common/helpers';
22

33
export const buttons = [
4-
{ title: 'first', action: { onClick: noop } },
5-
{ title: 'second', action: { href: 'some-url2', 'data-method': 'put' } },
6-
{ title: 'third', action: { onClick: noop } },
4+
{ title: 'first', action: { id: 1, onClick: noop } },
5+
{ title: 'second', action: { id: 2, href: 'some-url2', 'data-method': 'put' } },
6+
{ title: 'third', action: { id: 3, onClick: noop } },
7+
{ title: 'fourth', action: { id: 4, onClick: noop, disabled: true } },
78
];

webpack/assets/javascripts/react_app/components/common/ActionButtons/ActionButtons.js

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,95 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import PropTypes from 'prop-types';
3-
import { SplitButton, MenuItem, Button } from 'patternfly-react';
3+
import {
4+
Button,
5+
Dropdown,
6+
DropdownItem,
7+
DropdownList,
8+
MenuToggle,
9+
MenuToggleAction,
10+
} from '@patternfly/react-core';
11+
import './actionButtons.scss';
412

513
/**
614
* Generate a button or a dropdown of buttons
715
* @param {String} title The title of the button for the title and text inside the button
8-
* @param {Object} action action to preform when the button is click can be href with data-method or Onclick
9-
* @return {Function} button component or splitbutton component
16+
* @param {Object} action action to perform when the button is click can be href with data-method or Onclick
17+
* @return {Function} button component or splitbutton with menu toggle action component
1018
*/
1119
export const ActionButtons = ({ buttons }) => {
20+
const [isOpen, setIsOpen] = useState(false);
21+
const onToggleClick = () => setIsOpen(!isOpen);
22+
1223
if (!buttons.length) return null;
1324
if (buttons.length === 1)
1425
return (
15-
<Button bsSize="small" {...buttons[0].action}>
26+
<Button
27+
ouiaId={`action-button-${buttons[0].action?.id}`}
28+
size="sm"
29+
variant="primary"
30+
isDisabled={buttons[0].action?.disabled}
31+
{...buttons[0].action}
32+
>
1633
{buttons[0].title}
1734
</Button>
1835
);
19-
const firstButton = buttons.shift();
36+
37+
const [firstButton, ...restButtons] = buttons;
38+
2039
return (
21-
<SplitButton
22-
title={firstButton.title}
23-
{...firstButton.action}
24-
bsSize="small"
40+
<Dropdown
41+
ouiaId={`action-buttons-dropdown-${firstButton.action?.id}`}
42+
isOpen={isOpen}
43+
onOpenChange={openState => setIsOpen(openState)}
44+
toggle={toggleRef => (
45+
<MenuToggle
46+
ref={toggleRef}
47+
onClick={onToggleClick}
48+
isExpanded={isOpen}
49+
splitButtonOptions={{
50+
variant: 'action',
51+
items: [
52+
<MenuToggleAction
53+
id={`split-button-action-${firstButton.action?.id}-toggle-button`}
54+
key="split-action"
55+
aria-label={firstButton.title}
56+
onClick={firstButton.action?.onClick}
57+
>
58+
{firstButton.title}
59+
</MenuToggleAction>,
60+
],
61+
}}
62+
aria-label="Menu toggle with action split button"
63+
/>
64+
)}
65+
shouldFocusToggleOnSelect
2566
>
26-
{buttons.map(button => (
27-
<MenuItem key={button.title} title={button.title} {...button.action}>
28-
{button.title}
29-
</MenuItem>
30-
))}
31-
</SplitButton>
67+
<DropdownList className="action-buttons">
68+
{restButtons.map(button => (
69+
<DropdownItem
70+
ouiaId={`${button.action?.id}-dropdown-item-id`}
71+
key={`${button.action?.id}-dropdown-item-key`}
72+
title={button.title}
73+
onClick={button.action?.onClick}
74+
isDisabled={button.action?.disabled}
75+
>
76+
{button.title}
77+
</DropdownItem>
78+
))}
79+
</DropdownList>
80+
</Dropdown>
3281
);
3382
};
3483

3584
ActionButtons.propTypes = {
3685
buttons: PropTypes.arrayOf(
3786
PropTypes.shape({
38-
action: PropTypes.object,
87+
action: PropTypes.shape({
88+
id: PropTypes.number,
89+
onClick: PropTypes.func,
90+
href: PropTypes.string,
91+
disabled: PropTypes.bool,
92+
}),
3993
title: PropTypes.string,
4094
})
4195
),
Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,44 @@
1-
import { testComponentSnapshotsWithFixtures } from 'foremanReact/common/testHelpers';
1+
import React from 'react';
2+
import { screen, fireEvent, render, act } from '@testing-library/react';
3+
import '@testing-library/jest-dom/extend-expect';
4+
25
import { ActionButtons } from './ActionButtons';
36
import { buttons } from './ActionButtons.fixtures';
47

58
const fixtures = {
6-
'renders ActionButtons with 0 button': { buttons: [] },
7-
'renders ActionButtons with 1 button': { buttons: [buttons[0]] },
8-
'renders ActionButtons with 3 button': { buttons },
9+
none: { buttons: [] },
10+
one: { buttons: [buttons[0]] },
11+
many: { buttons },
912
};
1013

11-
describe('ActionButtons', () =>
12-
testComponentSnapshotsWithFixtures(ActionButtons, fixtures));
14+
describe('ActionButtons', () => {
15+
it('renders with 0 buttons', () => {
16+
render(<ActionButtons {...fixtures.none} />);
17+
expect(screen.queryByRole('button')).not.toBeInTheDocument();
18+
});
19+
20+
it('renders 1 button', () => {
21+
render(<ActionButtons {...fixtures.one} />);
22+
expect(screen.getByRole('button')).toHaveTextContent('first');
23+
});
24+
25+
it('renders 2 buttons initially and shows more after clicking toggle', async () => {
26+
render(<ActionButtons {...fixtures.many} />);
27+
const buttons = screen.getAllByRole('button');
28+
expect(buttons).toHaveLength(2);
29+
expect(screen.getByRole('button', { name: 'first' })).toBeInTheDocument();
30+
const toggleButton = screen.getByRole('button', {
31+
name: 'Menu toggle with action split button'
32+
});
33+
expect(toggleButton).toBeInTheDocument();
34+
35+
expect(screen.queryByText('second')).not.toBeInTheDocument();
36+
expect(screen.queryByText('third')).not.toBeInTheDocument();
37+
await act(async () => fireEvent.click(toggleButton));
38+
expect(screen.getByText('second')).toBeInTheDocument();
39+
expect(screen.getByText('third')).toBeInTheDocument();
40+
const dropdownItems = screen.getAllByRole('menuitem');
41+
expect(dropdownItems).toHaveLength(3);
42+
expect(dropdownItems[2]).toBeDisabled();
43+
});
44+
});

webpack/assets/javascripts/react_app/components/common/ActionButtons/__snapshots__/ActionButtons.test.js.snap

Lines changed: 0 additions & 49 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.pf-v5-c-menu__content {
2+
ul[role="menu"].action-buttons {
3+
margin-bottom: 0;
4+
}
5+
}

0 commit comments

Comments
 (0)