mirror of
https://gitlab.nic.cz/turris/reforis/foris-js.git
synced 2024-12-27 00:31:35 +01:00
Add ActionButtonWithModal component and remove RebootButton
This commit is contained in:
parent
087ecfa670
commit
7f9fc8e91b
124
src/common/ActionButtonWithModal/ActionButtonWithModal.js
Normal file
124
src/common/ActionButtonWithModal/ActionButtonWithModal.js
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019-2024 CZ.NIC z.s.p.o. (https://www.nic.cz/)
|
||||||
|
*
|
||||||
|
* This is free software, licensed under the GNU General Public License v3.
|
||||||
|
* See /LICENSE for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { useAPIPost } from "../../api/hooks";
|
||||||
|
import { API_STATE } from "../../api/utils";
|
||||||
|
import Button from "../../bootstrap/Button";
|
||||||
|
import {
|
||||||
|
Modal,
|
||||||
|
ModalHeader,
|
||||||
|
ModalBody,
|
||||||
|
ModalFooter,
|
||||||
|
} from "../../bootstrap/Modal";
|
||||||
|
import { useAlert } from "../../context/alertContext/AlertContext";
|
||||||
|
|
||||||
|
ActionButtonWithModal.propTypes = {
|
||||||
|
actionTrigger: PropTypes.elementType.isRequired,
|
||||||
|
actionUrl: PropTypes.string.isRequired,
|
||||||
|
modalTitle: PropTypes.string.isRequired,
|
||||||
|
modalMessage: PropTypes.string.isRequired,
|
||||||
|
modalActionText: PropTypes.string,
|
||||||
|
modalActionProps: PropTypes.object,
|
||||||
|
successMessage: PropTypes.string,
|
||||||
|
errorMessage: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
function ActionButtonWithModal({
|
||||||
|
actionTrigger: ActionTriggerComponent,
|
||||||
|
actionUrl,
|
||||||
|
modalTitle,
|
||||||
|
modalMessage,
|
||||||
|
modalActionText,
|
||||||
|
modalActionProps,
|
||||||
|
successMessage,
|
||||||
|
errorMessage,
|
||||||
|
}) {
|
||||||
|
const [triggered, setTriggered] = useState(false);
|
||||||
|
const [modalShown, setModalShown] = useState(false);
|
||||||
|
const [triggerActionStatus, triggerAction] = useAPIPost(actionUrl);
|
||||||
|
|
||||||
|
const [setAlert] = useAlert();
|
||||||
|
useEffect(() => {
|
||||||
|
if (triggerActionStatus.state === API_STATE.SUCCESS) {
|
||||||
|
setAlert(
|
||||||
|
successMessage || _("Action successful."),
|
||||||
|
API_STATE.SUCCESS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (triggerActionStatus.state === API_STATE.ERROR) {
|
||||||
|
setAlert(errorMessage || _("Action failed."));
|
||||||
|
}
|
||||||
|
}, [triggerActionStatus, setAlert, successMessage, errorMessage]);
|
||||||
|
|
||||||
|
const actionHandler = () => {
|
||||||
|
setTriggered(true);
|
||||||
|
triggerAction();
|
||||||
|
setModalShown(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ActionModal
|
||||||
|
shown={modalShown}
|
||||||
|
setShown={setModalShown}
|
||||||
|
onAction={actionHandler}
|
||||||
|
title={modalTitle}
|
||||||
|
message={modalMessage}
|
||||||
|
actionText={modalActionText}
|
||||||
|
actionProps={modalActionProps}
|
||||||
|
/>
|
||||||
|
<ActionTriggerComponent
|
||||||
|
loading={triggered}
|
||||||
|
disabled={triggered}
|
||||||
|
onClick={() => setModalShown(true)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionModal.propTypes = {
|
||||||
|
shown: PropTypes.bool.isRequired,
|
||||||
|
setShown: PropTypes.func.isRequired,
|
||||||
|
onAction: PropTypes.func.isRequired,
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
message: PropTypes.string.isRequired,
|
||||||
|
actionText: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
function ActionModal({
|
||||||
|
shown,
|
||||||
|
setShown,
|
||||||
|
onAction,
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
actionText,
|
||||||
|
actionProps,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Modal shown={shown} setShown={setShown}>
|
||||||
|
<ModalHeader setShown={setShown} title={title} />
|
||||||
|
<ModalBody>
|
||||||
|
<p className="mb-0">{message}</p>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button
|
||||||
|
className="btn-secondary"
|
||||||
|
onClick={() => setShown(false)}
|
||||||
|
>
|
||||||
|
{_("Cancel")}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={onAction} {...actionProps}>
|
||||||
|
{actionText || _("Confirm")}
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ActionButtonWithModal;
|
|
@ -1,90 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2019-2024 CZ.NIC z.s.p.o. (https://www.nic.cz/)
|
|
||||||
*
|
|
||||||
* This is free software, licensed under the GNU General Public License v3.
|
|
||||||
* See /LICENSE for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
|
||||||
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
|
|
||||||
import { useAPIPost } from "../api/hooks";
|
|
||||||
import { API_STATE } from "../api/utils";
|
|
||||||
import Button from "../bootstrap/Button";
|
|
||||||
import { Modal, ModalHeader, ModalBody, ModalFooter } from "../bootstrap/Modal";
|
|
||||||
import { useAlert } from "../context/alertContext/AlertContext";
|
|
||||||
import { ForisURLs } from "../utils/forisUrls";
|
|
||||||
|
|
||||||
RebootButton.propTypes = {
|
|
||||||
/** Additional props to be passed to the button */
|
|
||||||
props: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
function RebootButton(props) {
|
|
||||||
const [triggered, setTriggered] = useState(false);
|
|
||||||
const [modalShown, setModalShown] = useState(false);
|
|
||||||
const [triggerRebootStatus, triggerReboot] = useAPIPost(ForisURLs.reboot);
|
|
||||||
|
|
||||||
const [setAlert] = useAlert();
|
|
||||||
useEffect(() => {
|
|
||||||
if (triggerRebootStatus.state === API_STATE.ERROR) {
|
|
||||||
setAlert(_("Reboot request failed."));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const rebootHandler = () => {
|
|
||||||
setTriggered(true);
|
|
||||||
triggerReboot();
|
|
||||||
setModalShown(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<RebootModal
|
|
||||||
shown={modalShown}
|
|
||||||
setShown={setModalShown}
|
|
||||||
onReboot={rebootHandler}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
className="btn-danger"
|
|
||||||
loading={triggered}
|
|
||||||
disabled={triggered}
|
|
||||||
onClick={() => setModalShown(true)}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{_("Reboot")}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
RebootModal.propTypes = {
|
|
||||||
shown: PropTypes.bool.isRequired,
|
|
||||||
setShown: PropTypes.func.isRequired,
|
|
||||||
onReboot: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
function RebootModal({ shown, setShown, onReboot }) {
|
|
||||||
return (
|
|
||||||
<Modal shown={shown} setShown={setShown}>
|
|
||||||
<ModalHeader setShown={setShown} title={_("Warning!")} />
|
|
||||||
<ModalBody>
|
|
||||||
<p>{_("Are you sure you want to restart the router?")}</p>
|
|
||||||
</ModalBody>
|
|
||||||
<ModalFooter>
|
|
||||||
<Button
|
|
||||||
className="btn-secondary"
|
|
||||||
onClick={() => setShown(false)}
|
|
||||||
>
|
|
||||||
{_("Cancel")}
|
|
||||||
</Button>
|
|
||||||
<Button className="btn-danger" onClick={onReboot}>
|
|
||||||
{_("Confirm reboot")}
|
|
||||||
</Button>
|
|
||||||
</ModalFooter>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RebootButton;
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/)
|
* Copyright (C) 2019-2024 CZ.NIC z.s.p.o. (https://www.nic.cz/)
|
||||||
*
|
*
|
||||||
* This is free software, licensed under the GNU General Public License v3.
|
* This is free software, licensed under the GNU General Public License v3.
|
||||||
* See /LICENSE for more information.
|
* See /LICENSE for more information.
|
||||||
|
@ -18,15 +18,16 @@ import mockAxios from "jest-mock-axios";
|
||||||
import { mockJSONError } from "testUtils/network";
|
import { mockJSONError } from "testUtils/network";
|
||||||
import { mockSetAlert } from "testUtils/alertContextMock";
|
import { mockSetAlert } from "testUtils/alertContextMock";
|
||||||
|
|
||||||
import RebootButton from "../RebootButton";
|
import ActionButtonWithModal from "../ActionButtonWithModal/ActionButtonWithModal";
|
||||||
|
|
||||||
describe("<RebootButton/>", () => {
|
describe("<ActionButtonWithModal/>", () => {
|
||||||
let componentContainer;
|
let componentContainer;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<>
|
<>
|
||||||
<div id="modal-container" />
|
<div id="modal-container" />
|
||||||
<RebootButton />
|
<div id="alert-container" />
|
||||||
|
<ActionButtonWithModal />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
componentContainer = container;
|
componentContainer = container;
|
||||||
|
@ -37,27 +38,27 @@ describe("<RebootButton/>", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Render modal.", () => {
|
it("Render modal.", () => {
|
||||||
expect(queryByText(componentContainer, "Confirm reboot")).toBeNull();
|
expect(queryByText(componentContainer, "Confirm action")).toBeNull();
|
||||||
fireEvent.click(getByText(componentContainer, "Reboot"));
|
fireEvent.click(getByText(componentContainer, "Action"));
|
||||||
expect(componentContainer).toMatchSnapshot();
|
expect(componentContainer).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Confirm reboot.", () => {
|
it("Confirm action.", () => {
|
||||||
fireEvent.click(getByText(componentContainer, "Reboot"));
|
fireEvent.click(getByText(componentContainer, "action"));
|
||||||
fireEvent.click(getByText(componentContainer, "Confirm reboot"));
|
fireEvent.click(getByText(componentContainer, "Confirm action"));
|
||||||
expect(mockAxios.post).toHaveBeenCalledWith(
|
expect(mockAxios.post).toHaveBeenCalledWith(
|
||||||
"/reforis/api/reboot",
|
"/reforis/api/action",
|
||||||
undefined,
|
undefined,
|
||||||
expect.anything()
|
expect.anything()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Hold error.", async () => {
|
it("Hold error.", async () => {
|
||||||
fireEvent.click(getByText(componentContainer, "Reboot"));
|
fireEvent.click(getByText(componentContainer, "Action"));
|
||||||
fireEvent.click(getByText(componentContainer, "Confirm reboot"));
|
fireEvent.click(getByText(componentContainer, "Confirm action"));
|
||||||
mockJSONError();
|
mockJSONError();
|
||||||
await wait(() =>
|
await wait(() =>
|
||||||
expect(mockSetAlert).toBeCalledWith("Reboot request failed.")
|
expect(mockSetAlert).toBeCalledWith("Action request failed.")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -40,7 +40,7 @@ export { Spinner, SpinnerElement } from "./bootstrap/Spinner";
|
||||||
export { Modal, ModalBody, ModalFooter, ModalHeader } from "./bootstrap/Modal";
|
export { Modal, ModalBody, ModalFooter, ModalHeader } from "./bootstrap/Modal";
|
||||||
|
|
||||||
// Common
|
// Common
|
||||||
export { default as RebootButton } from "./common/RebootButton";
|
export { default as ActionButtonWithModal } from "./common/ActionButtonWithModal/ActionButtonWithModal";
|
||||||
export { default as WiFiSettings } from "./common/WiFiSettings/WiFiSettings";
|
export { default as WiFiSettings } from "./common/WiFiSettings/WiFiSettings";
|
||||||
export { default as ResetWiFiSettings } from "./common/WiFiSettings/ResetWiFiSettings";
|
export { default as ResetWiFiSettings } from "./common/WiFiSettings/ResetWiFiSettings";
|
||||||
export { default as RichTable } from "./common/RichTable/RichTable";
|
export { default as RichTable } from "./common/RichTable/RichTable";
|
||||||
|
|
|
@ -32,7 +32,7 @@ module.exports = {
|
||||||
description: "Set of main components.",
|
description: "Set of main components.",
|
||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
name: "Foris Form",
|
name: "ForisForm",
|
||||||
components: [
|
components: [
|
||||||
"src/form/components/ForisForm.js",
|
"src/form/components/ForisForm.js",
|
||||||
"src/form/components/alerts.js",
|
"src/form/components/alerts.js",
|
||||||
|
@ -42,14 +42,16 @@ module.exports = {
|
||||||
usageMode: "expand",
|
usageMode: "expand",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Rich Table",
|
name: "RichTable",
|
||||||
components: ["src/common/RichTable/RichTable.js"],
|
components: ["src/common/RichTable/RichTable.js"],
|
||||||
exampleMode: "expand",
|
exampleMode: "expand",
|
||||||
usageMode: "expand",
|
usageMode: "expand",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Reboot Button",
|
name: "ActionButtonWithModal",
|
||||||
components: ["src/common/RebootButton.js"],
|
components: [
|
||||||
|
"src/common/ActionButtonWithModal/ActionButtonWithModal.js",
|
||||||
|
],
|
||||||
exampleMode: "expand",
|
exampleMode: "expand",
|
||||||
usageMode: "expand",
|
usageMode: "expand",
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user