mirror of
				https://gitlab.nic.cz/turris/reforis/foris-js.git
				synced 2025-11-03 23:00:31 +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:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -51,4 +51,3 @@ coverage.xml
 | 
			
		||||
dist/
 | 
			
		||||
foris-*.tgz
 | 
			
		||||
styleguide/
 | 
			
		||||
testUtils
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										26
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -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": {
 | 
			
		||||
                "type": "opencollective",
 | 
			
		||||
                "url": "https://opencollective.com/browserslist"
 | 
			
		||||
            }
 | 
			
		||||
            "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": {
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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";
 | 
			
		||||
 
 | 
			
		||||
@@ -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([
 | 
			
		||||
							
								
								
									
										57
									
								
								src/context/customizationContext/CustomizationContext.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/context/customizationContext/CustomizationContext.js
									
									
									
									
									
										Normal 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 };
 | 
			
		||||
							
								
								
									
										3
									
								
								src/context/customizationContext/CustomizationContext.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/context/customizationContext/CustomizationContext.md
									
									
									
									
									
										Normal 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.
 | 
			
		||||
@@ -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();
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -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>
 | 
			
		||||
`;
 | 
			
		||||
@@ -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";
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								src/index.js
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/index.js
									
									
									
									
									
								
							@@ -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";
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
            <StaticRouter>
 | 
			
		||||
                <UIDReset>{children}</UIDReset>
 | 
			
		||||
            </StaticRouter>
 | 
			
		||||
            <CustomizationContextMock>
 | 
			
		||||
                <StaticRouter>
 | 
			
		||||
                    <UIDReset>{children}</UIDReset>
 | 
			
		||||
                </StaticRouter>
 | 
			
		||||
            </CustomizationContextMock>
 | 
			
		||||
        </AlertContextMock>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								src/testUtils/cutomizationContextMock.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/testUtils/cutomizationContextMock.js
									
									
									
									
									
										Normal 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 };
 | 
			
		||||
@@ -36,5 +36,6 @@ export const ForisURLs = {
 | 
			
		||||
    luci: "/cgi-bin/luci",
 | 
			
		||||
 | 
			
		||||
    // API
 | 
			
		||||
    about: `${REFORIS_API_URL_PREFIX}/about`,
 | 
			
		||||
    reboot: `${REFORIS_API_URL_PREFIX}/reboot`,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -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.",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user