1
0
mirror of https://gitlab.nic.cz/turris/reforis/foris-js.git synced 2024-12-25 00:11:36 +01:00

Merge branch 'add-customization-context' into 'dev'

Add CustomizationContext and custom hook

See merge request turris/reforis/foris-js!183
This commit is contained in:
Aleksandr Gumroian 2022-12-22 15:58:04 +01:00
commit 0f2344a005
18 changed files with 201 additions and 22 deletions

1
.gitignore vendored
View File

@ -51,4 +51,3 @@ coverage.xml
dist/
foris-*.tgz
styleguide/
testUtils

20
package-lock.json generated
View File

@ -4874,14 +4874,20 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001309",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001309.tgz",
"integrity": "sha512-Pl8vfigmBXXq+/yUz1jUwULeq9xhMJznzdc/xwl4WclDAuebcTHVefpz8lE/bMI+UN7TOkSSe7B7RnZd6+dzjA==",
"version": "1.0.30001441",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz",
"integrity": "sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==",
"dev": true,
"funding": {
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
}
]
},
"node_modules/capture-exit": {
"version": "2.0.0",
@ -22831,9 +22837,9 @@
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001309",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001309.tgz",
"integrity": "sha512-Pl8vfigmBXXq+/yUz1jUwULeq9xhMJznzdc/xwl4WclDAuebcTHVefpz8lE/bMI+UN7TOkSSe7B7RnZd6+dzjA==",
"version": "1.0.30001441",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz",
"integrity": "sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==",
"dev": true
},
"capture-exit": {

View File

@ -14,7 +14,7 @@ import { ForisURLs } from "../utils/forisUrls";
import { Button } from "../bootstrap/Button";
import { Modal, ModalHeader, ModalBody, ModalFooter } from "../bootstrap/Modal";
import { useAlert } from "../alertContext/AlertContext";
import { useAlert } from "../context/alertContext/AlertContext";
export function RebootButton(props) {
const [triggered, setTriggered] = useState(false);

View File

@ -9,7 +9,7 @@ import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import { Button } from "../../bootstrap/Button";
import { useAlert } from "../../alertContext/AlertContext";
import { useAlert } from "../../context/alertContext/AlertContext";
import { ALERT_TYPES } from "../../bootstrap/Alert";
import { useAPIPost } from "../../api/hooks";
import { API_STATE } from "../../api/utils";

View File

@ -8,8 +8,8 @@
import React, { useState, useContext, useCallback } from "react";
import PropTypes from "prop-types";
import { Alert, ALERT_TYPES } from "../bootstrap/Alert";
import { Portal } from "../utils/Portal";
import { Alert, ALERT_TYPES } from "../../bootstrap/Alert";
import { Portal } from "../../utils/Portal";
AlertContextProvider.propTypes = {
children: PropTypes.oneOfType([

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2019-2022 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, { useContext, useEffect } from "react";
import PropTypes from "prop-types";
import { useAPIGet } from "../../api/hooks";
import { ForisURLs } from "../../utils/forisUrls";
import { Spinner } from "../../bootstrap/Spinner";
CustomizationContextProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]),
};
function CustomizationContextProvider({ children }) {
const { CustomizationContext } = window;
const [getCustomizationResponse, getCustomization] = useAPIGet(
ForisURLs.about
);
useEffect(() => {
getCustomization();
}, [getCustomization]);
if (getCustomizationResponse.state !== "success") {
return <Spinner fullScreen />;
}
const deviceDetails = getCustomizationResponse.data || {};
const isCustomized = !!(
deviceDetails &&
deviceDetails.customization !== undefined &&
deviceDetails.customization === "shield"
);
return (
<CustomizationContext.Provider value={{ deviceDetails, isCustomized }}>
{children}
</CustomizationContext.Provider>
);
}
function useCustomizationContext() {
const { CustomizationContext } = window;
return useContext(CustomizationContext);
}
export { CustomizationContextProvider, useCustomizationContext };

View File

@ -0,0 +1,3 @@
It provides customization context to the children. `CustomizationContext` allows
using `useCustomizationContext` in components to check if the reForis UI is
customized or not for specific devices.

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2019-2022 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 from "react";
import { render, wait, getByText } from "customTestRender";
import mockAxios from "jest-mock-axios";
import {
useCustomizationContext,
CustomizationContextProvider,
} from "../CustomizationContext";
const CUSTOM = "Description / component for customized reForis (Shield)";
const ORIGINAL = "Description / component for original reForis (other devices)";
const CustomizationTest = () => {
const { isCustomized } = useCustomizationContext();
return <p>{isCustomized ? CUSTOM : ORIGINAL}</p>;
};
describe("CustomizationContext", () => {
let componentContainer;
beforeEach(() => {
const { container } = render(
<CustomizationContextProvider>
<CustomizationTest />
</CustomizationContextProvider>
);
componentContainer = container;
});
it("should render component without customization", async () => {
mockAxios.mockResponse({ data: {} });
await wait(() => getByText(componentContainer, ORIGINAL));
expect(componentContainer).toMatchSnapshot();
});
it("should render customized component", async () => {
mockAxios.mockResponse({ data: { customization: "shield" } });
await wait(() => getByText(componentContainer, CUSTOM));
expect(componentContainer).toMatchSnapshot();
});
});

View File

@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CustomizationContext should render component without customization 1`] = `
<div>
<p>
Description / component for original reForis (other devices)
</p>
</div>
`;
exports[`CustomizationContext should render customized component 1`] = `
<div>
<p>
Description / component for customized reForis (Shield)
</p>
</div>
`;

View File

@ -13,7 +13,7 @@ import { ALERT_TYPES } from "../../bootstrap/Alert";
import { API_STATE } from "../../api/utils";
import { formFieldsSize } from "../../bootstrap/constants";
import { Spinner } from "../../bootstrap/Spinner";
import { useAlert } from "../../alertContext/AlertContext";
import { useAlert } from "../../context/alertContext/AlertContext";
import { useAPIPost } from "../../api/hooks";
import { useForisModule, useForm } from "../hooks";

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2021 CZ.NIC z.s.p.o. (http://www.nic.cz/)
* Copyright (C) 2019-2022 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.
@ -90,4 +90,13 @@ export {
} from "./utils/validations";
// Alert context
export { AlertContextProvider, useAlert } from "./alertContext/AlertContext";
export {
AlertContextProvider,
useAlert,
} from "./context/alertContext/AlertContext";
// Customization context
export {
CustomizationContextProvider,
useCustomizationContext,
} from "./context/customizationContext/CustomizationContext";

View File

@ -14,6 +14,7 @@ import { render } from "@testing-library/react";
import PropTypes from "prop-types";
import { AlertContextMock } from "./alertContextMock";
import { CustomizationContextMock } from "./cutomizationContextMock";
Wrapper.propTypes = {
children: PropTypes.oneOfType([
@ -25,9 +26,11 @@ Wrapper.propTypes = {
function Wrapper({ children }) {
return (
<AlertContextMock>
<CustomizationContextMock>
<StaticRouter>
<UIDReset>{children}</UIDReset>
</StaticRouter>
</CustomizationContextMock>
</AlertContextMock>
);
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2019-2022 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 from "react";
window.CustomizationContext = React.createContext();
const deviceDetails = {};
const isCustomized = jest.fn();
function CustomizationContextMock({ children }) {
return (
<CustomizationContext.Provider value={(deviceDetails, isCustomized)}>
{children}
</CustomizationContext.Provider>
);
}
export { CustomizationContextMock };

View File

@ -36,5 +36,6 @@ export const ForisURLs = {
luci: "/cgi-bin/luci",
// API
about: `${REFORIS_API_URL_PREFIX}/about`,
reboot: `${REFORIS_API_URL_PREFIX}/reboot`,
};

View File

@ -43,7 +43,7 @@ module.exports = {
},
{
name: "Alert Context",
components: ["src/alertContext/AlertContext.js"],
components: ["src/context/alertContext/AlertContext.js"],
exampleMode: "expand",
usageMode: "expand",
},
@ -51,6 +51,14 @@ module.exports = {
sectionDepth: 1,
},
{
name: "Customization Context",
components: [
"src/context/customizationContext/CustomizationContext.js",
],
exampleMode: "expand",
usageMode: "expand",
},
{
name: "Bootstrap components",
description: "Set of bootstrap components.",