Skip to content

Commit

Permalink
Merge pull request #104 from YotaYota/feature.cnaas-456
Browse files Browse the repository at this point in the history
Management Domain Modal
  • Loading branch information
indy-independence committed May 7, 2024
2 parents 509ac54 + 93c3b73 commit e0f8f59
Show file tree
Hide file tree
Showing 12 changed files with 1,178 additions and 301 deletions.
3 changes: 2 additions & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ TEMPLATES_WEB_URL=https://localhost
SETTINGS_WEB_URL=https://localhost
MONITORING_WEB_URL=https://localhost
OIDC_ENABLED=true
PERMISSIONS_DISABLED=true
PERMISSIONS_DISABLED=true
MGMT_DOMAIN_CORE_ENABLED=false
3 changes: 2 additions & 1 deletion example.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ TEMPLATES_WEB_URL=https://localhost
SETTINGS_WEB_URL=https://localhost
MONITORING_WEB_URL=https://localhost
OIDC_ENABLED=true
PERMISSIONS_DISABLED=false
PERMISSIONS_DISABLED=false
MGMT_DOMAIN_CORE_ENABLED=false
167 changes: 167 additions & 0 deletions public/components/DeviceList/AddMgmtDomainModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import React, { useState } from "react";
import {
Button,
Form,
FormField,
FormGroup,
FormInput,
FormSelect,
Icon,
Modal,
ModalActions,
ModalContent,
ModalDescription,
ModalHeader,
} from "semantic-ui-react";
import { postData } from "../../utils/sendData";

function AddMgmtDomainModal({
deviceA,
deviceBCandidates,
isOpen,
onAdd,
closeAction,
}) {
const [formData, setFormData] = useState({ ipv4: "", ipv6: "", vlan: "" });
const [errors, setErrors] = useState([]);

const { deviceB, ipv4, ipv6, vlan } = formData;

const deviceBOptions =
deviceBCandidates?.map((device, index) => ({
key: device.hostname,
text: device.hostname,
value: index,
})) || [];

function clearForm() {
setErrors([]);
setFormData({ ipv4: "", ipv6: "", vlan: "" });
}

async function handleAdd() {
const credentials = localStorage.getItem("token");
const payload = {
device_a: deviceA,
device_b: deviceB,
ipv4_gw: ipv4,
ipv6_gw: ipv6,
vlan,
};
postData(
`${process.env.API_URL}/api/v1.0/mgmtdomains`,
credentials,
payload,
)
.then((resp) => {
clearForm();
console.log(resp);
onAdd(resp.data.added_mgmtdomain.id);
})
.catch(async (errResp) => {
console.log(errResp);
const errObj = await errResp.json();
setErrors(errObj.message);
});
}

function handleChange(event) {
const { name, value } = event.target;
setFormData((prev) => ({ ...prev, [name]: value }));
}

function handleSelected(e, data) {
const selectedValue = data.value;
setFormData((prev) => ({
...prev,
deviceB: deviceBOptions[selectedValue].key,
}));
}

function handleCancel() {
setFormData({ ipv4: "", ipv6: "", vlan: "" });
setErrors([]);
closeAction();
}

return (
<Modal open={isOpen} onClose={handleCancel}>
<ModalHeader>Add Management Domain</ModalHeader>
<ModalContent>
<ModalDescription>
<Form>
<FormGroup grouped>
<FormField>
<FormSelect
inline
id="mgmt_add_domain_b_select"
name="domainB"
label={
<>
<span style={{ fontWeight: "lighter" }}>
Devices in managament domain:
</span>
{deviceA},{" "}
</>
}
placeholder="device_b"
selection
options={deviceBOptions}
onChange={handleSelected}
/>
</FormField>

<FormField>
<FormInput
id="mgmt_add_ipv4_input"
label="IPv4 Gateway"
name="ipv4"
type="text"
value={ipv4}
onChange={handleChange}
/>
</FormField>

<FormField>
<FormInput
id="mgmt_add_ipv6_input"
label="IPv6 Gateway"
name="ipv6"
type="text"
value={ipv6}
onChange={handleChange}
/>
</FormField>

<FormField>
<FormInput
id="mgmt_add_vlan_input"
label="VLAN ID"
name="vlan"
type="text"
value={vlan}
onChange={handleChange}
/>
</FormField>
</FormGroup>
</Form>
<ul id="mgmt_add_error_list" style={{ color: "red" }}>
{errors.map((err) => (
<li key={err}>{err}</li>
))}
</ul>
</ModalDescription>
</ModalContent>
<ModalActions>
<Button color="black" onClick={handleCancel}>
Cancel <Icon name="cancel" />
</Button>
<Button color="green" onClick={handleAdd}>
Add <Icon name="checkmark" />
</Button>
</ModalActions>
</Modal>
);
}

export default AddMgmtDomainModal;
115 changes: 115 additions & 0 deletions public/components/DeviceList/AddMgmtDomainModal.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";

import AddMgmtDomainModal from "./AddMgmtDomainModal";

import { postData as mockPostData } from "../../utils/sendData";

jest.mock("../../utils/sendData");
mockPostData.mockResolvedValue({
success: "ok",
data: { added_mgmtdomain: { id: 66 } },
});

beforeEach(() => {
mockPostData.mockClear();
jest
.spyOn(Storage.prototype, "getItem")
.mockReturnValue("localStorageMockValue");
});

afterAll(() => {
global.Storage.prototype.getItem.mockReset();
});

const mockCloseAction = jest.fn();
function renderComponent() {
render(
<AddMgmtDomainModal
deviceA="deviceA"
deviceBCandidates={[{ hostname: "a" }, { hostname: "b" }]}
isOpen
onAdd={jest.fn()}
closeAction={mockCloseAction}
/>,
);
}

test("renders", async () => {
renderComponent();

expect(screen.getByRole("button", { name: /add/i })).toBeInTheDocument();
expect(screen.getByRole("button", { name: /cancel/i })).toBeInTheDocument();
// with no errors
expect(screen.queryAllByRole("listitem").length).toBe(0);
});

test("type input and click add", async () => {
renderComponent();

const domainBSelect = screen.getByText("device_b");
userEvent.click(domainBSelect);
expect(domainBSelect.textContent).toBe("device_b");
const dropdownOptions = screen.getAllByRole("option");
await userEvent.click(dropdownOptions[1]);

const ipv4Input = screen.getByLabelText(/ipv4 gateway/i);
await userEvent.type(ipv4Input, "1.2.3.4/24");

const ipv6Input = screen.getByLabelText(/ipv6 gateway/i);
await userEvent.type(ipv6Input, "::1234:5678:91.123.4.56");

const vlanInput = screen.getByLabelText(/vlan id/i);
await userEvent.type(vlanInput, "1950");

const addButton = screen.getByRole("button", { name: /add/i });
await userEvent.click(addButton);

expect(mockPostData).toHaveBeenCalledTimes(1);
expect(mockPostData).toHaveBeenCalledWith(
expect.stringContaining("https://"),
expect.stringContaining("local"),
{
device_a: "deviceA",
device_b: "b",
ipv4_gw: "1.2.3.4/24",
ipv6_gw: "::1234:5678:91.123.4.56",
vlan: "1950",
},
);
});

test("type input and click cancel should clear fields", async () => {
renderComponent();

const domainBSelect = screen.getByText("device_b");
const dropdownOptions = screen.getAllByRole("option");
expect(domainBSelect).toBeVisible();
userEvent.click(domainBSelect);
await userEvent.click(dropdownOptions[1]);
expect(domainBSelect).not.toBeVisible();

const ipv4Input = screen.getByLabelText(/ipv4 gateway/i);
await userEvent.type(ipv4Input, "1.2.3.4/24");
expect(ipv4Input.value).toBe("1.2.3.4/24");

const ipv6Input = screen.getByLabelText(/ipv6 gateway/i);
await userEvent.type(ipv6Input, "::1234:5678:91.123.4.56");
expect(ipv6Input.value).toBe("::1234:5678:91.123.4.56");

const vlanInput = screen.getByLabelText(/vlan id/i);
await userEvent.type(vlanInput, "1950");
expect(vlanInput.value).toBe("1950");

const cancelButton = screen.getByRole("button", { name: /cancel/i });
await userEvent.click(cancelButton);

expect(mockPostData).not.toHaveBeenCalled();
expect(mockCloseAction).toHaveBeenCalledTimes(1);

expect(ipv4Input.value).toBeFalsy();
expect(ipv6Input.value).toBeFalsy();
expect(vlanInput.value).toBeFalsy();
});
Loading

0 comments on commit e0f8f59

Please sign in to comment.