CEC-4525: add support for /tags endpoint and implement a new action for it (#361)
* add action for adding tags
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DropDownButton Render 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
class="MuiFormControl-root MuiFormControl-marginNormal MuiFormControl-fullWidth MuiTextField-root css-17vbkzs-MuiFormControl-root-MuiTextField-root"
|
||||
data-testid="text-input-list"
|
||||
>
|
||||
<label
|
||||
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-sizeSmall MuiInputLabel-outlined MuiFormLabel-colorPrimary Mui-required MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-sizeSmall MuiInputLabel-outlined css-1pysi21-MuiFormLabel-root-MuiInputLabel-root"
|
||||
data-shrink="false"
|
||||
for="mui-0"
|
||||
id="mui-0-label"
|
||||
>
|
||||
The input label (use commas to add multiple)
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="MuiFormLabel-asterisk MuiInputLabel-asterisk css-wgai2y-MuiFormLabel-asterisk"
|
||||
>
|
||||
|
||||
*
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-sizeSmall css-md26zr-MuiInputBase-root-MuiOutlinedInput-root"
|
||||
>
|
||||
<input
|
||||
aria-invalid="false"
|
||||
class="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputSizeSmall css-1n4twyu-MuiInputBase-input-MuiOutlinedInput-input"
|
||||
id="mui-0"
|
||||
name="text"
|
||||
required=""
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<fieldset
|
||||
aria-hidden="true"
|
||||
class="MuiOutlinedInput-notchedOutline css-1d3z3hw-MuiOutlinedInput-notchedOutline"
|
||||
>
|
||||
<legend
|
||||
class="css-yjsfm1"
|
||||
>
|
||||
<span>
|
||||
The input label (use commas to add multiple)
|
||||
|
||||
*
|
||||
</span>
|
||||
</legend>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="MuiBox-root css-6km64s"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
97
src/components/Controls/TextInputList/index.jsx
Normal file
97
src/components/Controls/TextInputList/index.jsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Cancel } from "@mui/icons-material";
|
||||
import { TextField } from "@mui/material";
|
||||
import { Box } from "@mui/system";
|
||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||
|
||||
const TextInput = ({ text, handleDelete }) => {
|
||||
return (
|
||||
<Box sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "2px",
|
||||
p: "2px 4px",
|
||||
backgroundColor: "#ccc",
|
||||
borderRadius: 1,
|
||||
}}>
|
||||
{text}
|
||||
<Cancel
|
||||
sx={{
|
||||
color: "#666",
|
||||
fontSize: "16px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => handleDelete(text)}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
const TextInputList = ({
|
||||
onChange = () => {},
|
||||
validate = () => {},
|
||||
label
|
||||
}) => {
|
||||
const [textList, setTextList] = useState([]);
|
||||
const [input, setInput] = useState("");
|
||||
|
||||
const { setMessage } = useStatusContext();
|
||||
|
||||
const handleDelete = (textToDelete) => {
|
||||
setTextList(textList => textList.filter(text => text !== textToDelete));
|
||||
}
|
||||
|
||||
const handleOnChange = (event) => {
|
||||
const char = event.nativeEvent.data;
|
||||
if (char === ",") {
|
||||
try {
|
||||
if (validate) validate(input);
|
||||
setTextList(textList => [...textList, input]);
|
||||
setInput("");
|
||||
} catch {
|
||||
setMessage(`"${input}" is not valid.`);
|
||||
}
|
||||
} else {
|
||||
setInput(event.target.value);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
onChange(input.length ? [...textList, input] : [...textList]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [textList, input]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TextField
|
||||
data-testid="text-input-list"
|
||||
name="text"
|
||||
label={`${label} (use commas to add multiple)`}
|
||||
value={input}
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
required
|
||||
size="small"
|
||||
fullWidth
|
||||
onChange={handleOnChange}
|
||||
/>
|
||||
|
||||
<Box sx={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
gap: 1,
|
||||
pr: 1,
|
||||
}}>
|
||||
{textList.map((text) => (
|
||||
<TextInput
|
||||
text={text}
|
||||
handleDelete={handleDelete}
|
||||
key={text}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TextInputList;
|
||||
57
src/components/Controls/TextInputList/index.test.jsx
Normal file
57
src/components/Controls/TextInputList/index.test.jsx
Normal file
@@ -0,0 +1,57 @@
|
||||
jest.mock("../../Contexts/StatusContext");
|
||||
|
||||
import React from "react";
|
||||
import { render, waitFor } from "@testing-library/react";
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import TextInputList from ".";
|
||||
import addSnapshotSerializer from "../../../utils/snapshot";
|
||||
|
||||
describe("DropDownButton", () => {
|
||||
beforeAll(() => {
|
||||
addSnapshotSerializer(expect);
|
||||
});
|
||||
|
||||
it("Render", async () => {
|
||||
const { container } = render(
|
||||
<TextInputList
|
||||
label={"The input label"}
|
||||
/>
|
||||
);
|
||||
await waitFor(() => {
|
||||
/* render */
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("properly adds tag after comma", async () => {
|
||||
const { getByText, getByTestId } = render(
|
||||
<TextInputList
|
||||
label={"The input label"}
|
||||
payload={[]}
|
||||
/>
|
||||
);
|
||||
|
||||
const [inputEl] = getByTestId("text-input-list").getElementsByTagName("input");
|
||||
userEvent.type(inputEl, "tag1");
|
||||
userEvent.type(inputEl, ",");
|
||||
expect(getByText("tag1").nodeName).toBe("DIV");
|
||||
});
|
||||
|
||||
it("properly passes payload to callback", async () => {
|
||||
const mockCallback = jest.fn();
|
||||
|
||||
const { getByTestId } = render(
|
||||
<TextInputList
|
||||
label={"The input label"}
|
||||
onChange={mockCallback}
|
||||
/>
|
||||
);
|
||||
|
||||
const [inputEl] = getByTestId("text-input-list").getElementsByTagName("input");
|
||||
userEvent.type(inputEl, "tag1");
|
||||
userEvent.type(inputEl, ",");
|
||||
userEvent.type(inputEl, "tag2");
|
||||
expect(mockCallback).toHaveBeenCalledWith(["tag1", "tag2"]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user