CEC-4499: add bulk update configs support (#357)
* add taskRunner util * add bulk update config flow
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DownloadFileLink Render 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-label="choose action"
|
||||
class="MuiButtonGroup-root MuiButtonGroup-contained"
|
||||
role="group"
|
||||
>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary MuiButton-containedPrimary"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiButton-label"
|
||||
>
|
||||
Action One
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
aria-haspopup="menu"
|
||||
aria-label="select action"
|
||||
class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary MuiButton-containedPrimary MuiButton-containedSizeSmall MuiButton-sizeSmall"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
|
||||
data-testid="ArrowDropDownIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="m7 10 5 5 5-5z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`DropDownButton Render 1`] = `
|
||||
<div>
|
||||
<div
|
||||
aria-label="choose action"
|
||||
class="MuiButtonGroup-root MuiButtonGroup-contained"
|
||||
role="group"
|
||||
>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary MuiButton-containedPrimary"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiButton-label"
|
||||
>
|
||||
Action One
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
aria-haspopup="menu"
|
||||
aria-label="select action"
|
||||
class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary MuiButton-containedPrimary MuiButton-containedSizeSmall MuiButton-sizeSmall"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
|
||||
data-testid="ArrowDropDownIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="m7 10 5 5 5-5z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
109
src/components/Controls/DropDownButton/index.jsx
Normal file
109
src/components/Controls/DropDownButton/index.jsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import { useRef, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
ClickAwayListener,
|
||||
Grow,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
Paper,
|
||||
Popper,
|
||||
} from "@mui/material";
|
||||
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
||||
|
||||
const DropDownButton = ({ actions = [], payload = [] }) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
const anchorRef = useRef(null);
|
||||
|
||||
const handleClick = () => {
|
||||
actions[selectedIndex].trigger(...payload);
|
||||
};
|
||||
|
||||
const handleMenuItemClick = (event, index) => {
|
||||
setSelectedIndex(index);
|
||||
setOpen(false);
|
||||
}
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen(open => !open);
|
||||
};
|
||||
|
||||
const handleClose = (event) => {
|
||||
if (
|
||||
anchorRef.current &&
|
||||
anchorRef.current.contains(event.target)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ButtonGroup
|
||||
color="primary"
|
||||
variant="contained"
|
||||
ref={anchorRef}
|
||||
aria-label="choose action"
|
||||
>
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
disabled={actions[selectedIndex].disabled}
|
||||
>
|
||||
{actions[selectedIndex].name}
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
aria-controls={open ? 'split-button-menu' : undefined}
|
||||
aria-expanded={open ? 'true' : undefined}
|
||||
aria-label="select action"
|
||||
aria-haspopup="menu"
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<ArrowDropDownIcon />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<Popper
|
||||
sx={{
|
||||
zIndex: 100,
|
||||
}}
|
||||
open={open}
|
||||
anchorEl={anchorRef.current}
|
||||
role={undefined}
|
||||
transition
|
||||
disablePortal
|
||||
>
|
||||
{({ TransitionProps, placement }) => (
|
||||
<Grow
|
||||
{...TransitionProps}
|
||||
style={{
|
||||
transformOrigin:
|
||||
placement === 'bottom' ? 'center top' : 'center bottom',
|
||||
}}
|
||||
>
|
||||
<Paper>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<MenuList id="split-button-menu" autoFocusItem>
|
||||
{actions.map((action, index) => (
|
||||
<MenuItem
|
||||
key={action.name}
|
||||
disabled={actions[index].disabled}
|
||||
selected={index === selectedIndex}
|
||||
onClick={(event) => handleMenuItemClick(event, index)}
|
||||
>
|
||||
{action.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
</ClickAwayListener>
|
||||
</Paper>
|
||||
</Grow>
|
||||
)}
|
||||
</Popper>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DropDownButton;
|
||||
80
src/components/Controls/DropDownButton/index.test.jsx
Normal file
80
src/components/Controls/DropDownButton/index.test.jsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import React from "react";
|
||||
import { fireEvent, render, waitFor, screen } from "@testing-library/react";
|
||||
|
||||
import DropDownButton from ".";
|
||||
import addSnapshotSerializer from "../../../utils/snapshot";
|
||||
|
||||
describe("DropDownButton", () => {
|
||||
beforeAll(() => {
|
||||
addSnapshotSerializer(expect);
|
||||
});
|
||||
|
||||
it("Render", async () => {
|
||||
const actions = [
|
||||
{
|
||||
name: "Action One",
|
||||
disabled: false,
|
||||
trigger: (paramOne, paramTwo) => {}
|
||||
},
|
||||
{
|
||||
name: "Action Two",
|
||||
disabled: false,
|
||||
trigger: (paramOne, paramTwo) => {}
|
||||
},
|
||||
];
|
||||
|
||||
const { container } = render(
|
||||
<DropDownButton
|
||||
actions={actions}
|
||||
payload={["somePayload", "someOtherPayload"]}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => {
|
||||
/* render */
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("properly disables an action", async () => {
|
||||
const actions = [
|
||||
{
|
||||
name: "Disabled Action",
|
||||
disabled: true,
|
||||
trigger: () => {}
|
||||
},
|
||||
];
|
||||
|
||||
const { getByText } = render(
|
||||
<DropDownButton
|
||||
actions={actions}
|
||||
payload={[]}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => {
|
||||
/* render */
|
||||
});
|
||||
const buttonEl = getByText("Disabled Action").parentElement;
|
||||
expect(buttonEl).toHaveProperty("disabled", true);
|
||||
});
|
||||
|
||||
it("properly passes payload to callback", async () => {
|
||||
const actions = [
|
||||
{
|
||||
name: "Action One",
|
||||
disabled: false,
|
||||
trigger: jest.fn(),
|
||||
},
|
||||
];
|
||||
|
||||
render(
|
||||
<DropDownButton
|
||||
actions={actions}
|
||||
payload={["somePayload", "somePayload2"]}
|
||||
/>
|
||||
);
|
||||
|
||||
const buttonEl = screen.getByText("Action One");
|
||||
fireEvent.click(buttonEl);
|
||||
expect(actions[0].trigger).toHaveBeenCalledWith("somePayload", "somePayload2");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user