diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 76aa24e..c5c0aea 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,44 +1,44 @@
image: node:8-alpine
stages:
- - test
- - build
- - publish
+ - test
+ - build
+ - publish
before_script:
- - apk add make
- - npm install
+ - apk add make
+ - npm install
test:
- stage: test
- script:
- - make test
+ stage: test
+ script:
+ - make test
lint:
- stage: test
- script:
- - make lint
+ stage: test
+ script:
+ - make lint
build:
- stage: build
- script:
- - make pack
- artifacts:
- paths:
- - dist/foris-*.tgz
+ stage: build
+ script:
+ - make pack
+ artifacts:
+ paths:
+ - dist/foris-*.tgz
publish_beta:
- stage: publish
- only:
- refs:
- - dev
- script:
- - make publish-beta
+ stage: publish
+ only:
+ refs:
+ - dev
+ script:
+ - make publish-beta
publish_latest:
- stage: publish
- only:
- refs:
- - master
- script:
- - make publish-latest
+ stage: publish
+ only:
+ refs:
+ - master
+ script:
+ - make publish-latest
diff --git a/README.md b/README.md
index cafdbfa..3805a6d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# foris-js
+
Set of utils and common React elements for reForis.
## Publishing package
@@ -6,24 +7,27 @@ Set of utils and common React elements for reForis.
### Beta versions
Each commit to `dev` branch will result in publishing a new version of library
-tagged `beta`. Versions names are based on commit SHA, e.g.
+tagged `beta`. Versions names are based on commit SHA, e.g.
`foris@0.1.0-beta.d9073aa4`.
### Preparing a release
1. Crete a merge request to `dev` branch with version bumped
2. When merging add `[skip ci]` to commit message to prevent publishing
-unnecessary version
+ unnecessary version
3. Create a merge request from `dev` to `master` branch
4. New version should be published automatically
## Manually managed dependencies
-Because of ` ` component it's required to use exposed `ReactRouterDOM`
-object from `react-router-dom` library. `ReactRouterDOM` is exposed by
+
+Because of ` ` component it's required to use exposed
+`ReactRouterDOM` object from `react-router-dom` library. `ReactRouterDOM` is
+exposed by
[reForis](https://gitlab.labs.nic.cz/turris/reforis/reforis/blob/master/js/webpack.config.js).
It can be done by following steps:
-
-1. Setting `react-router-dom` as `peerDependencies` and `devDependencies` in `package.json`.
+
+1. Setting `react-router-dom` as `peerDependencies` and `devDependencies` in
+ `package.json`.
2. Adding the following rules to `externals` in `webpack.conf.js` of the plugin:
```js
@@ -34,11 +38,15 @@ externals: {
```
### Docs
+
Build or watch docs to get more info about library:
+
```bash
make docs
```
+
or
+
```bash
make docs-watch
```
diff --git a/babel.config.js b/babel.config.js
index 07f13e2..6b3639b 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1,9 +1,4 @@
module.exports = {
- presets: [
- "@babel/preset-env",
- "@babel/preset-react",
- ],
- plugins: [
- "@babel/plugin-transform-runtime",
- ],
+ presets: ["@babel/preset-env", "@babel/preset-react"],
+ plugins: ["@babel/plugin-transform-runtime"],
};
diff --git a/docs/development.md b/docs/development.md
index 882c1c0..585213c 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -1,12 +1,15 @@
-Sooner or later you will face with situation when you want/need to make some changes in the library.
-Then the most important tool for you it's [`npm link`](https://docs.npmjs.com/cli/link).
+Sooner or later you will face with situation when you want/need to make some
+changes in the library. Then the most important tool for you it's
+[`npm link`](https://docs.npmjs.com/cli/link).
-Please, notice that it will not work if you link library just from root of the repo. It happens due to location of
-sources `./src`. You need to pack library first `make pack` and then link it from `./dist` directory.
+Please, notice that it will not work if you link library just from root of the
+repo. It happens due to location of sources `./src`. You need to pack library
+first `make pack` and then link it from `./dist` directory.
-Yeah it's not such comfortable solution for development. But it can fixed by writing small script similar as `make pack`
-but with linking every file and directory from `./src` to the some directory and linking then from it. Notice that you
-need to link `package.json` and `package-lock.json` as well.
+Yeah it's not such comfortable solution for development. But it can fixed by
+writing small script similar as `make pack` but with linking every file and
+directory from `./src` to the some directory and linking then from it. Notice
+that you need to link `package.json` and `package-lock.json` as well.
So step by step:
diff --git a/docs/intro.md b/docs/intro.md
index 624b987..4637cbc 100644
--- a/docs/intro.md
+++ b/docs/intro.md
@@ -1,4 +1,6 @@
-Foris JS library is set of components and utils for Foris JS application and plugins.
+Foris JS library is set of components and utils for Foris JS application and
+plugins.
-Please notice that all of these components or utils are used in reForis and plugins. If you like to study by example I would
-recommend to full-text search these repos.
+Please notice that all of these components or utils are used in reForis and
+plugins. If you like to study by example I would recommend to full-text search
+these repos.
diff --git a/jest.config.js b/jest.config.js
index 401852e..da04a4a 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -27,7 +27,5 @@ module.exports = {
globals: {
TZ: "utc",
},
- transformIgnorePatterns: [
- "node_modules/(?!(react-datetime)/)",
- ],
+ transformIgnorePatterns: ["node_modules/(?!(react-datetime)/)"],
};
diff --git a/src/alertContext/AlertContext.js b/src/alertContext/AlertContext.js
index fc5b0ec..bf01371 100644
--- a/src/alertContext/AlertContext.js
+++ b/src/alertContext/AlertContext.js
@@ -22,9 +22,12 @@ function AlertContextProvider({ children }) {
const { AlertContext } = window;
const [alert, setAlert] = useState(null);
- const setAlertWrapper = useCallback((message, type = ALERT_TYPES.DANGER) => {
- setAlert({ message, type });
- }, [setAlert]);
+ const setAlertWrapper = useCallback(
+ (message, type = ALERT_TYPES.DANGER) => {
+ setAlert({ message, type });
+ },
+ [setAlert]
+ );
const dismissAlert = useCallback(() => setAlert(null), [setAlert]);
@@ -38,7 +41,7 @@ function AlertContextProvider({ children }) {
)}
- { children }
+ {children}
>
);
diff --git a/src/alertContext/AlertContext.md b/src/alertContext/AlertContext.md
index 48e4f44..339d393 100644
--- a/src/alertContext/AlertContext.md
+++ b/src/alertContext/AlertContext.md
@@ -1,4 +1,5 @@
-It provides alert context to children. `AlertContext` allows using `useAlert` in components.
+It provides alert context to children. `AlertContext` allows using `useAlert` in
+components.
-Notice that `
` should be presented in HTML doc to get it work (In reForis it's already done
-with base Jinja2 templates).
+Notice that `
` should be presented in HTML doc to get
+it work (In reForis it's already done with base Jinja2 templates).
diff --git a/src/alertContext/__tests__/AlertContext.test.js b/src/alertContext/__tests__/AlertContext.test.js
index 78408e7..c1c67bb 100644
--- a/src/alertContext/__tests__/AlertContext.test.js
+++ b/src/alertContext/__tests__/AlertContext.test.js
@@ -6,9 +6,7 @@
*/
import React from "react";
-import {
- render, getByText, queryByText, fireEvent,
-} from "customTestRender";
+import { render, getByText, queryByText, fireEvent } from "customTestRender";
import { useAlert, AlertContextProvider } from "../AlertContext";
@@ -31,7 +29,7 @@ describe("AlertContext", () => {
const { container } = render(
- ,
+
);
componentContainer = container;
});
diff --git a/src/api/hooks.js b/src/api/hooks.js
index 04d6ce3..a19732c 100644
--- a/src/api/hooks.js
+++ b/src/api/hooks.js
@@ -5,13 +5,16 @@
* See /LICENSE for more information.
*/
-import {
- useCallback, useEffect, useReducer, useState,
-} from "react";
+import { useCallback, useEffect, useReducer, useState } from "react";
import { ForisURLs } from "../utils/forisUrls";
import {
- API_ACTIONS, API_METHODS, API_STATE, getErrorPayload, HEADERS, TIMEOUT,
+ API_ACTIONS,
+ API_METHODS,
+ API_STATE,
+ getErrorPayload,
+ HEADERS,
+ TIMEOUT,
} from "./utils";
const DATA_METHODS = ["POST", "PATCH", "PUT"];
@@ -23,76 +26,83 @@ function createAPIHook(method) {
data: null,
});
- const sendRequest = useCallback(async ({ data, suffix } = {}) => {
- const headers = { ...HEADERS };
- if (contentType) {
- headers["Content-Type"] = contentType;
- }
-
- dispatch({ type: API_ACTIONS.INIT });
- try {
- // Prepare request
- const request = API_METHODS[method];
- const config = {
- timeout: TIMEOUT,
- headers,
- };
- const url = suffix ? `${urlRoot}/${suffix}` : urlRoot;
-
- // Make request
- let result;
- if (DATA_METHODS.includes(method)) {
- result = await request(url, data, config);
- } else {
- result = await request(url, config);
+ const sendRequest = useCallback(
+ async ({ data, suffix } = {}) => {
+ const headers = { ...HEADERS };
+ if (contentType) {
+ headers["Content-Type"] = contentType;
}
- // Process request result
- dispatch({
- type: API_ACTIONS.SUCCESS,
- payload: result.data,
- });
- } catch (error) {
- const errorPayload = getErrorPayload(error);
- dispatch({
- type: API_ACTIONS.FAILURE,
- status: error.response && error.response.status,
- payload: errorPayload,
- });
- }
- }, [urlRoot, contentType]);
+ dispatch({ type: API_ACTIONS.INIT });
+ try {
+ // Prepare request
+ const request = API_METHODS[method];
+ const config = {
+ timeout: TIMEOUT,
+ headers,
+ };
+ const url = suffix ? `${urlRoot}/${suffix}` : urlRoot;
+
+ // Make request
+ let result;
+ if (DATA_METHODS.includes(method)) {
+ result = await request(url, data, config);
+ } else {
+ result = await request(url, config);
+ }
+
+ // Process request result
+ dispatch({
+ type: API_ACTIONS.SUCCESS,
+ payload: result.data,
+ });
+ } catch (error) {
+ const errorPayload = getErrorPayload(error);
+ dispatch({
+ type: API_ACTIONS.FAILURE,
+ status: error.response && error.response.status,
+ payload: errorPayload,
+ });
+ }
+ },
+ [urlRoot, contentType]
+ );
return [state, sendRequest];
};
}
function APIReducer(state, action) {
switch (action.type) {
- case API_ACTIONS.INIT:
- return {
- ...state,
- state: API_STATE.SENDING,
- };
- case API_ACTIONS.SUCCESS:
- return {
- state: API_STATE.SUCCESS,
- data: action.payload,
- };
- case API_ACTIONS.FAILURE:
- if (action.status === 403) {
- window.location.assign(ForisURLs.login);
- }
+ case API_ACTIONS.INIT:
+ return {
+ ...state,
+ state: API_STATE.SENDING,
+ };
+ case API_ACTIONS.SUCCESS:
+ return {
+ state: API_STATE.SUCCESS,
+ data: action.payload,
+ };
+ case API_ACTIONS.FAILURE:
+ if (action.status === 403) {
+ window.location.assign(ForisURLs.login);
+ }
- // Not an API error - should be rethrown.
- if (action.payload && action.payload.stack && action.payload.message) {
- throw (action.payload);
- }
+ // Not an API error - should be rethrown.
+ if (
+ action.payload &&
+ action.payload.stack &&
+ action.payload.message
+ ) {
+ throw action.payload;
+ }
- return {
- state: API_STATE.ERROR,
- data: action.payload,
- };
- default:
- throw new Error();
+ return {
+ state: API_STATE.ERROR,
+ data: action.payload,
+ };
+ default:
+ throw new Error();
}
}
@@ -102,11 +112,10 @@ const useAPIPatch = createAPIHook("PATCH");
const useAPIPut = createAPIHook("PUT");
const useAPIDelete = createAPIHook("DELETE");
-export {
- useAPIGet, useAPIPost, useAPIPatch, useAPIPut, useAPIDelete,
-};
+export { useAPIGet, useAPIPost, useAPIPatch, useAPIPut, useAPIDelete };
-export function useAPIPolling(endpoint, delay = 1000, until) { // delay ms
+export function useAPIPolling(endpoint, delay = 1000, until) {
+ // delay ms
const [state, setState] = useState({ state: API_STATE.INIT });
const [getResponse, get] = useAPIGet(endpoint);
diff --git a/src/api/utils.js b/src/api/utils.js
index c8e340c..ba6d0d4 100644
--- a/src/api/utils.js
+++ b/src/api/utils.js
@@ -43,8 +43,10 @@ function getCookie(name) {
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
- if (cookie.substring(0, name.length + 1) === (`${name}=`)) {
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ if (cookie.substring(0, name.length + 1) === `${name}=`) {
+ cookieValue = decodeURIComponent(
+ cookie.substring(name.length + 1)
+ );
break;
}
}
diff --git a/src/bootstrap/Alert.js b/src/bootstrap/Alert.js
index 5671f89..f460931 100644
--- a/src/bootstrap/Alert.js
+++ b/src/bootstrap/Alert.js
@@ -35,12 +35,16 @@ Alert.defaultProps = {
type: ALERT_TYPES.DANGER,
};
-export function Alert({
- type, onDismiss, children,
-}) {
+export function Alert({ type, onDismiss, children }) {
return (
- {onDismiss ? × : false}
+ {onDismiss ? (
+
+ ×
+
+ ) : (
+ false
+ )}
{children}
);
diff --git a/src/bootstrap/Alert.md b/src/bootstrap/Alert.md
index 787b5fb..99c836f 100644
--- a/src/bootstrap/Alert.md
+++ b/src/bootstrap/Alert.md
@@ -1,21 +1,21 @@
Bootstrap alert component.
```jsx
-import {useState} from 'react';
+import { useState } from "react";
-function AlertExample(){
+function AlertExample() {
const [alert, setAlert] = useState(true);
if (alert)
- return setAlert(false)}
- >
- Some warning out there!
- ;
- return setAlert(true)}
- >Show alert again ;
-};
-
+ return (
+ setAlert(false)}>
+ Some warning out there!
+
+ );
+ return (
+ setAlert(true)}>
+ Show alert again
+
+ );
+}
+ ;
```
diff --git a/src/bootstrap/Button.js b/src/bootstrap/Button.js
index 413128f..84ad558 100644
--- a/src/bootstrap/Button.js
+++ b/src/bootstrap/Button.js
@@ -25,22 +25,29 @@ Button.propTypes = {
};
export function Button({
- className, loading, forisFormSize, children, ...props
+ className,
+ loading,
+ forisFormSize,
+ children,
+ ...props
}) {
let buttonClass = className ? `btn ${className}` : "btn btn-primary ";
if (forisFormSize) {
buttonClass = `${buttonClass} col-sm-12 col-md-3 col-lg-2`;
}
- const span = loading
- ? : null;
+ const span = loading ? (
+
+ ) : null;
return (
{span}
- {" "}
{span ? " " : null}
- {" "}
{children}
);
diff --git a/src/bootstrap/Button.md b/src/bootstrap/Button.md
index dd9d2a6..1867f73 100644
--- a/src/bootstrap/Button.md
+++ b/src/bootstrap/Button.md
@@ -11,5 +11,7 @@ Can be used without parameters:
Using loading spinner:
```jsx
-Loading...
+
+ Loading...
+
```
diff --git a/src/bootstrap/CheckBox.js b/src/bootstrap/CheckBox.js
index d6dbce8..0e2dbcb 100644
--- a/src/bootstrap/CheckBox.js
+++ b/src/bootstrap/CheckBox.js
@@ -22,9 +22,7 @@ CheckBox.defaultProps = {
disabled: false,
};
-export function CheckBox({
- label, helpText, disabled, ...props
-}) {
+export function CheckBox({ label, helpText, disabled, ...props }) {
const uid = useUID();
return (
@@ -34,12 +32,15 @@ export function CheckBox({
type="checkbox"
id={uid}
disabled={disabled}
-
{...props}
/>
{label}
- {helpText && {helpText} }
+ {helpText && (
+
+ {helpText}
+
+ )}
diff --git a/src/bootstrap/Checkbox.md b/src/bootstrap/Checkbox.md
index a4a5bbf..ccf1c43 100644
--- a/src/bootstrap/Checkbox.md
+++ b/src/bootstrap/Checkbox.md
@@ -1,16 +1,17 @@
-Checkbox with label Bootstrap component with predefined sizes and structure for using in foris forms.
-
-All additional `props` are passed to the ` ` HTML component.
+Checkbox with label Bootstrap component with predefined sizes and structure for
+using in foris forms.
+All additional `props` are passed to the ` ` HTML
+component.
```js
-import {useState} from 'react';
+import { useState } from "react";
const [value, setValue] = useState(false);
setValue(event.target.value)}
-/>
+ onChange={(event) => setValue(event.target.value)}
+/>;
```
diff --git a/src/bootstrap/DataTimeInput.js b/src/bootstrap/DataTimeInput.js
index 676fb46..0241ad3 100644
--- a/src/bootstrap/DataTimeInput.js
+++ b/src/bootstrap/DataTimeInput.js
@@ -38,14 +38,17 @@ const DEFAULT_DATE_FORMAT = "YYYY-MM-DD";
const DEFAULT_TIME_FORMAT = "HH:mm:ss";
export function DataTimeInput({
- value, onChange, isValidDate, dateFormat, timeFormat, children, ...props
+ value,
+ onChange,
+ isValidDate,
+ dateFormat,
+ timeFormat,
+ children,
+ ...props
}) {
function renderInput(datetimeProps) {
return (
-
+
{children}
);
@@ -54,8 +57,12 @@ export function DataTimeInput({
return (
{
- dataTime.isValid() ? setError(null) : setError('Invalid value!');
-},[dataTime]);
-
+useEffect(() => {
+ dataTime.isValid() ? setError(null) : setError("Invalid value!");
+}, [dataTime]);
+
setDataTime(value)}
-/>
+ helpText="Example helptext..."
+ onChange={(value) => setDataTime(value)}
+/>;
```
diff --git a/src/bootstrap/DownloadButton.js b/src/bootstrap/DownloadButton.js
index 13d1de1..6d5611b 100644
--- a/src/bootstrap/DownloadButton.js
+++ b/src/bootstrap/DownloadButton.js
@@ -23,11 +23,7 @@ DownloadButton.defaultProps = {
export function DownloadButton({ href, className, children }) {
return (
-
+
{children}
);
diff --git a/src/bootstrap/DownloadButton.md b/src/bootstrap/DownloadButton.md
index f96deef..e70e3d6 100644
--- a/src/bootstrap/DownloadButton.md
+++ b/src/bootstrap/DownloadButton.md
@@ -1,6 +1,9 @@
Hyperlink with apperance of a button.
-It has `download` attribute, which prevents closing WebSocket connection on Firefox. See [related issue](https://bugzilla.mozilla.org/show_bug.cgi?id=858538) for more details.
+It has `download` attribute, which prevents closing WebSocket connection on
+Firefox. See
+[related issue](https://bugzilla.mozilla.org/show_bug.cgi?id=858538) for more
+details.
```js
Download
diff --git a/src/bootstrap/EmailInput.md b/src/bootstrap/EmailInput.md
index b9ac8bc..d96ae95 100644
--- a/src/bootstrap/EmailInput.md
+++ b/src/bootstrap/EmailInput.md
@@ -1,18 +1,19 @@
-Bootstrap component of email input with label with predefined sizes and structure for using in foris forms.
-It use built-in browser email address checking. It's only meaningful using inside `
+;
```
diff --git a/src/bootstrap/FileInput.md b/src/bootstrap/FileInput.md
index 9c7c482..8dcbe09 100644
--- a/src/bootstrap/FileInput.md
+++ b/src/bootstrap/FileInput.md
@@ -1,9 +1,10 @@
-Bootstrap component for file input. Includes label and has predefined sizes and structure for using in foris forms.
+Bootstrap component for file input. Includes label and has predefined sizes and
+structure for using in foris forms.
All additional `props` are passed to the ` ` HTML component.
```js
-import { useState } from 'react';
+import { useState } from "react";
const [files, setFiles] = useState([]);
@@ -15,27 +16,33 @@ const label = files.length === 1 ? files[0].name : "Choose file";
files={files}
label={label}
helpText="Will be uploaded"
- onChange={event=>setFiles(event.target.files)}
+ onChange={(event) => setFiles(event.target.files)}
/>
-
+;
```
### FileInput with multiple files
+
```js
-import { useState } from 'react';
+import { useState } from "react";
const [files, setFiles] = useState([]);
// Note that files is not an array but FileList.
-const label = files.length > 0 ? Array.from(files).map(file=>file.name).join(", ") : "Choose files";
+const label =
+ files.length > 0
+ ? Array.from(files)
+ .map((file) => file.name)
+ .join(", ")
+ : "Choose files";
+;
```
diff --git a/src/bootstrap/Input.js b/src/bootstrap/Input.js
index ea9c301..658522a 100644
--- a/src/bootstrap/Input.js
+++ b/src/bootstrap/Input.js
@@ -25,25 +25,38 @@ Input.propTypes = {
/** Base bootstrap input component. */
export function Input({
- type, label, helpText, error, className, children, labelClassName, groupClassName, ...props
+ type,
+ label,
+ helpText,
+ error,
+ className,
+ children,
+ labelClassName,
+ groupClassName,
+ ...props
}) {
const uid = useUID();
- const inputClassName = `form-control ${className || ""} ${(error ? "is-invalid" : "")}`.trim();
+ const inputClassName = `form-control ${className || ""} ${
+ error ? "is-invalid" : ""
+ }`.trim();
return (
-
{label}
+
+ {label}
+
{children}
{error ?
{error}
: null}
- {helpText ?
{helpText} : null}
+ {helpText ? (
+
{helpText}
+ ) : null}
);
}
diff --git a/src/bootstrap/Modal.css b/src/bootstrap/Modal.css
index b057caa..9cc827c 100644
--- a/src/bootstrap/Modal.css
+++ b/src/bootstrap/Modal.css
@@ -10,6 +10,6 @@
.modal.show {
display: block;
animation-name: modalFade;
- animation-duration: .3s;
+ animation-duration: 0.3s;
background: rgba(0, 0, 0, 0.2);
}
diff --git a/src/bootstrap/Modal.js b/src/bootstrap/Modal.js
index d7d69e6..5c080c9 100644
--- a/src/bootstrap/Modal.js
+++ b/src/bootstrap/Modal.js
@@ -26,9 +26,7 @@ Modal.propTypes = {
]).isRequired,
};
-export function Modal({
- shown, setShown, scrollable, children,
-}) {
+export function Modal({ shown, setShown, scrollable, children }) {
const dialogRef = useRef();
useClickOutside(dialogRef, () => setShown(false));
@@ -38,12 +36,12 @@ export function Modal({
-
- {children}
-
+
{children}
@@ -59,7 +57,11 @@ export function ModalHeader({ setShown, title }) {
return (
{title}
- setShown(false)}>
+ setShown(false)}
+ >
×
@@ -85,9 +87,5 @@ ModalFooter.propTypes = {
};
export function ModalFooter({ children }) {
- return (
-
- {children}
-
- );
+ return {children}
;
}
diff --git a/src/bootstrap/Modal.md b/src/bootstrap/Modal.md
index e34e256..1744070 100644
--- a/src/bootstrap/Modal.md
+++ b/src/bootstrap/Modal.md
@@ -1,31 +1,36 @@
Bootstrap modal component.
-it's required to have an element `` somewhere on the page since modals are rendered in portals.
+it's required to have an element `
` somewhere on
+the page since modals are rendered in portals.
```js
-
+
```
```js
-import {ModalHeader, ModalBody, ModalFooter} from './Modal';
+import { ModalHeader, ModalBody, ModalFooter } from "./Modal";
-import {useState} from 'react';
+import { useState } from "react";
const [shown, setShown] = useState(false);
<>
-
- Bla bla bla...
+
+
+ Bla bla bla...
+
- setShown(false)}
- >Skip it
+ >
+ Skip it
+
-
-
setShown(true)}>
+
+ setShown(true)}>
Show modal
->
+>;
```
diff --git a/src/bootstrap/NumberInput.css b/src/bootstrap/NumberInput.css
index ec3ad49..f25019c 100644
--- a/src/bootstrap/NumberInput.css
+++ b/src/bootstrap/NumberInput.css
@@ -4,7 +4,7 @@ input[type="number"] {
appearance: textfield;
}
-input[type=number]::-webkit-inner-spin-button,
-input[type=number]::-webkit-outer-spin-button {
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
diff --git a/src/bootstrap/NumberInput.js b/src/bootstrap/NumberInput.js
index e8dc59a..2b4200d 100644
--- a/src/bootstrap/NumberInput.js
+++ b/src/bootstrap/NumberInput.js
@@ -20,10 +20,7 @@ NumberInput.propTypes = {
/** Help text message. */
helpText: PropTypes.string,
/** Number value. */
- value: PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.number,
- ]),
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** Function called when value changes. */
onChange: PropTypes.func.isRequired,
/** Additional description dispaled to the right of input value. */
@@ -34,15 +31,21 @@ NumberInput.defaultProps = {
value: 0,
};
-export function NumberInput({
- onChange, inlineText, value, ...props
-}) {
+export function NumberInput({ onChange, inlineText, value, ...props }) {
function updateValue(initialValue, difference) {
onChange({ target: { value: initialValue + difference } });
}
- const enableIncrease = useConditionalTimeout({ callback: updateValue }, value, 1);
- const enableDecrease = useConditionalTimeout({ callback: updateValue }, value, -1);
+ const enableIncrease = useConditionalTimeout(
+ { callback: updateValue },
+ value,
+ 1
+ );
+ const enableDecrease = useConditionalTimeout(
+ { callback: updateValue },
+ value,
+ -1
+ );
return (
diff --git a/src/bootstrap/NumberInput.md b/src/bootstrap/NumberInput.md
index 098efdf..1106437 100644
--- a/src/bootstrap/NumberInput.md
+++ b/src/bootstrap/NumberInput.md
@@ -1,17 +1,18 @@
-Bootstrap component of number input with label with predefined sizes and structure for using in foris forms.
+Bootstrap component of number input with label with predefined sizes and
+structure for using in foris forms.
All additional `props` are passed to the ` ` HTML component.
```js
-import {useState} from 'react';
+import { useState } from "react";
const [value, setValue] = useState(42);
setValue(event.target.value)}
-/>
+ min="33"
+ max="54"
+ onChange={(event) => setValue(event.target.value)}
+/>;
```
diff --git a/src/bootstrap/PasswordInput.js b/src/bootstrap/PasswordInput.js
index 6670eaf..ee93928 100644
--- a/src/bootstrap/PasswordInput.js
+++ b/src/bootstrap/PasswordInput.js
@@ -31,22 +31,24 @@ export function PasswordInput({ withEye, ...props }) {
autoComplete={isHidden ? "new-password" : null}
{...props}
>
- {withEye
- ? (
-
- {
- e.preventDefault();
- setHidden((shouldBeHidden) => !shouldBeHidden);
- }}
- >
-
-
-
- )
- : null}
+ {withEye ? (
+
+ {
+ e.preventDefault();
+ setHidden((shouldBeHidden) => !shouldBeHidden);
+ }}
+ >
+
+
+
+ ) : null}
);
}
diff --git a/src/bootstrap/PasswordInput.md b/src/bootstrap/PasswordInput.md
index c0f2ed4..33436d1 100644
--- a/src/bootstrap/PasswordInput.md
+++ b/src/bootstrap/PasswordInput.md
@@ -1,17 +1,18 @@
-Password Bootstrap component input with label and predefined sizes and structure for using in foris forms.
-Can be used with "eye" button, see example.
+Password Bootstrap component input with label and predefined sizes and structure
+for using in foris forms. Can be used with "eye" button, see example.
-All additional `props` are passed to the ` ` HTML component.
+All additional `props` are passed to the ` ` HTML
+component.
```js
-import {useState} from 'react';
-const [value, setValue] = useState('secret');
+import { useState } from "react";
+const [value, setValue] = useState("secret");
setValue(event.target.value)}
-/>
+ onChange={(event) => setValue(event.target.value)}
+/>;
```
diff --git a/src/bootstrap/RadioSet.js b/src/bootstrap/RadioSet.js
index 72bbda2..c9fede5 100644
--- a/src/bootstrap/RadioSet.js
+++ b/src/bootstrap/RadioSet.js
@@ -15,26 +15,27 @@ RadioSet.propTypes = {
/** RadioSet label . */
label: PropTypes.string,
/** Choices . */
- choices: PropTypes.arrayOf(PropTypes.shape({
- /** Choice lable . */
- label: PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.element,
- PropTypes.node,
- PropTypes.arrayOf(PropTypes.node),
- ]).isRequired,
- /** Choice value . */
- value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
- })).isRequired,
+ choices: PropTypes.arrayOf(
+ PropTypes.shape({
+ /** Choice lable . */
+ label: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.element,
+ PropTypes.node,
+ PropTypes.arrayOf(PropTypes.node),
+ ]).isRequired,
+ /** Choice value . */
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
+ .isRequired,
+ })
+ ).isRequired,
/** Initial value . */
value: PropTypes.string,
/** Help text message . */
helpText: PropTypes.string,
};
-export function RadioSet({
- name, label, choices, value, helpText, ...props
-}) {
+export function RadioSet({ name, label, choices, value, helpText, ...props }) {
const uid = useUID();
const radios = choices.map((choice, key) => {
const id = `${name}-${key}`;
@@ -47,7 +48,6 @@ export function RadioSet({
value={choice.value}
helpText={choice.helpText}
checked={choice.value === value}
-
{...props}
/>
);
@@ -55,9 +55,15 @@ export function RadioSet({
return (
- {label && {label} }
+ {label && (
+
+ {label}
+
+ )}
{radios}
- {helpText && {helpText} }
+ {helpText && (
+ {helpText}
+ )}
);
}
@@ -73,21 +79,28 @@ Radio.propTypes = {
helpText: PropTypes.string,
};
-export function Radio({
- label, id, helpText, ...props
-}) {
+export function Radio({ label, id, helpText, ...props }) {
return (
<>
-
+
- {label}
- {helpText && {helpText} }
+
+ {label}
+
+ {helpText && (
+
+ {helpText}
+
+ )}
>
);
diff --git a/src/bootstrap/RadioSet.md b/src/bootstrap/RadioSet.md
index 13c3338..1a01b0e 100644
--- a/src/bootstrap/RadioSet.md
+++ b/src/bootstrap/RadioSet.md
@@ -1,15 +1,16 @@
-Set of radio Bootstrap component input with label and predefined sizes and structure for using in foris forms.
+Set of radio Bootstrap component input with label and predefined sizes and
+structure for using in foris forms.
All additional `props` are passed to the `
` HTML component.
Unless `helpText` is set for one of the options they are displayed inline.
```js
-import {useState} from 'react';
-const CHOICES=[
- {value:'one',label:'1'},
- {value:'two',label:'2'},
- {value:'three',label:'3'},
+import { useState } from "react";
+const CHOICES = [
+ { value: "one", label: "1" },
+ { value: "two", label: "2" },
+ { value: "three", label: "3" },
];
const [value, setValue] = useState(CHOICES[0].value);
@@ -17,10 +18,10 @@ const [value, setValue] = useState(CHOICES[0].value);
{/*Yeah, it gets event, not value!*/}
setValue(event.target.value)}
+ onChange={(event) => setValue(event.target.value)}
/>
Selected value: {value}
->
+>;
```
diff --git a/src/bootstrap/Select.js b/src/bootstrap/Select.js
index 5dfd7d1..c60e282 100644
--- a/src/bootstrap/Select.js
+++ b/src/bootstrap/Select.js
@@ -15,35 +15,30 @@ Select.propTypes = {
/** Choices if form of {value : "Label",...}. */
choices: PropTypes.object.isRequired,
/** Current value. */
- value: PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.number,
- ]).isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
/** Help text message. */
helpText: PropTypes.string,
};
-export function Select({
- label, choices, helpText, ...props
-}) {
+export function Select({ label, choices, helpText, ...props }) {
const uid = useUID();
- const options = Object.keys(choices).sort(
- (a, b) => a - b || a.toString().localeCompare(b.toString()),
- ).map(
- (key) => {choices[key]} ,
- );
+ const options = Object.keys(choices)
+ .sort((a, b) => a - b || a.toString().localeCompare(b.toString()))
+ .map((key) => (
+
+ {choices[key]}
+
+ ));
return (
{label}
-
+
{options}
- {helpText ? {helpText} : null}
+ {helpText ? (
+ {helpText}
+ ) : null}
);
}
diff --git a/src/bootstrap/Select.md b/src/bootstrap/Select.md
index 1663183..acbac8c 100644
--- a/src/bootstrap/Select.md
+++ b/src/bootstrap/Select.md
@@ -1,13 +1,14 @@
-Select with options Bootstrap component input with label and predefined sizes and structure for using in foris forms.
+Select with options Bootstrap component input with label and predefined sizes
+and structure for using in foris forms.
All additional `props` are passed to the `` HTML component.
```js
-import {useState} from 'react';
-const CHOICES={
- apple:'Apple',
- banana:'Banana',
- peach:'Peach',
+import { useState } from "react";
+const CHOICES = {
+ apple: "Apple",
+ banana: "Banana",
+ peach: "Peach",
};
const [value, setValue] = useState(Object.keys(CHOICES)[0]);
@@ -17,9 +18,9 @@ const [value, setValue] = useState(Object.keys(CHOICES)[0]);
label="Fruit"
value={value}
choices={CHOICES}
- onChange={event=>setValue(event.target.value)}
+ onChange={(event) => setValue(event.target.value)}
/>
Selected choice label: {CHOICES[value]}
Selected choice value: {value}
->
+>;
```
diff --git a/src/bootstrap/Spinner.css b/src/bootstrap/Spinner.css
index 432b529..59fece3 100644
--- a/src/bootstrap/Spinner.css
+++ b/src/bootstrap/Spinner.css
@@ -5,7 +5,7 @@
}
.spinner-fs-background {
- background-color: rgba(2, 2, 2, .5);
+ background-color: rgba(2, 2, 2, 0.5);
color: rgb(230, 230, 230);
position: fixed;
width: 100%;
diff --git a/src/bootstrap/Spinner.js b/src/bootstrap/Spinner.js
index 5ea2a5d..e9993ef 100644
--- a/src/bootstrap/Spinner.js
+++ b/src/bootstrap/Spinner.js
@@ -25,12 +25,12 @@ Spinner.defaultProps = {
fullScreen: false,
};
-export function Spinner({
- fullScreen, children, className,
-}) {
+export function Spinner({ fullScreen, children, className }) {
if (!fullScreen) {
return (
-
+
{children}
);
@@ -61,7 +61,9 @@ export function SpinnerElement({ small, className, children }) {
return (
<>
diff --git a/src/bootstrap/Switch.js b/src/bootstrap/Switch.js
index 4113189..1af8edb 100644
--- a/src/bootstrap/Switch.js
+++ b/src/bootstrap/Switch.js
@@ -16,29 +16,33 @@ Switch.propTypes = {
PropTypes.node,
PropTypes.arrayOf(PropTypes.node),
]).isRequired,
- id: PropTypes.string.isRequired,
helpText: PropTypes.string,
- switchHeading: PropTypes.string,
+ switchHeading: PropTypes.bool,
};
-export function Switch({
- label, id, helpText, switchHeading, ...props
-}) {
+export function Switch({ label, helpText, switchHeading, ...props }) {
const uid = useUID();
return (
-
);
diff --git a/src/bootstrap/TextInput.md b/src/bootstrap/TextInput.md
index 944d01c..4125289 100644
--- a/src/bootstrap/TextInput.md
+++ b/src/bootstrap/TextInput.md
@@ -1,15 +1,16 @@
-Text Bootstrap component input with label and predefined sizes and structure for using in foris forms.
+Text Bootstrap component input with label and predefined sizes and structure for
+using in foris forms.
All additional `props` are passed to the `
` HTML component.
```js
-import {useState} from 'react';
-const [value, setValue] = useState('Bla bla');
+import { useState } from "react";
+const [value, setValue] = useState("Bla bla");
setValue(event.target.value)}
-/>
+ onChange={(event) => setValue(event.target.value)}
+/>;
```
diff --git a/src/bootstrap/__tests__/Button.test.js b/src/bootstrap/__tests__/Button.test.js
index b599573..3249526 100644
--- a/src/bootstrap/__tests__/Button.test.js
+++ b/src/bootstrap/__tests__/Button.test.js
@@ -14,19 +14,18 @@ import { Button } from "../Button";
describe(" ", () => {
it("Render button correctly", () => {
const { container } = render(Test Button );
- expect(container.firstChild)
- .toMatchSnapshot();
+ expect(container.firstChild).toMatchSnapshot();
});
it("Render button with custom classes", () => {
- const { container } = render(Test Button );
- expect(container.firstChild)
- .toMatchSnapshot();
+ const { container } = render(
+ Test Button
+ );
+ expect(container.firstChild).toMatchSnapshot();
});
it("Render button with spinner", () => {
const { container } = render(Test Button );
- expect(container.firstChild)
- .toMatchSnapshot();
+ expect(container.firstChild).toMatchSnapshot();
});
});
diff --git a/src/bootstrap/__tests__/CheckBox.test.js b/src/bootstrap/__tests__/CheckBox.test.js
index 26f35f3..4776404 100644
--- a/src/bootstrap/__tests__/CheckBox.test.js
+++ b/src/bootstrap/__tests__/CheckBox.test.js
@@ -18,22 +18,16 @@ describe(" ", () => {
label="Test label"
checked
helpText="Some help text"
- onChange={() => {
- }}
- />,
+ onChange={() => {}}
+ />
);
- expect(container.firstChild)
- .toMatchSnapshot();
+ expect(container.firstChild).toMatchSnapshot();
});
it("Render uncheked checkbox", () => {
const { container } = render(
- ,
+
);
- expect(container.firstChild)
- .toMatchSnapshot();
+ expect(container.firstChild).toMatchSnapshot();
});
});
diff --git a/src/bootstrap/__tests__/DownloadButton.test.js b/src/bootstrap/__tests__/DownloadButton.test.js
index 5f9108a..6d82743 100644
--- a/src/bootstrap/__tests__/DownloadButton.test.js
+++ b/src/bootstrap/__tests__/DownloadButton.test.js
@@ -13,7 +13,11 @@ import { DownloadButton } from "../DownloadButton";
describe(" ", () => {
it("should have download attribute", () => {
- const { container } = render(Test Button );
+ const { container } = render(
+
+ Test Button
+
+ );
expect(container.firstChild.getAttribute("download")).not.toBeNull();
});
});
diff --git a/src/bootstrap/__tests__/NumberInput.test.js b/src/bootstrap/__tests__/NumberInput.test.js
index dbd43dc..1a83f00 100644
--- a/src/bootstrap/__tests__/NumberInput.test.js
+++ b/src/bootstrap/__tests__/NumberInput.test.js
@@ -7,9 +7,7 @@
import React from "react";
-import {
- render, fireEvent, getByLabelText, wait,
-} from "customTestRender";
+import { render, fireEvent, getByLabelText, wait } from "customTestRender";
import { NumberInput } from "../NumberInput";
@@ -24,7 +22,7 @@ describe(" ", () => {
helpText="Some help text"
value={1}
onChange={onChangeMock}
- />,
+ />
);
componentContainer = container;
});
@@ -36,12 +34,16 @@ describe(" ", () => {
it("Increase number with button", async () => {
const increaseButton = getByLabelText(componentContainer, "Increase");
fireEvent.mouseDown(increaseButton);
- await wait(() => expect(onChangeMock).toHaveBeenCalledWith({ target: { value: 2 } }));
+ await wait(() =>
+ expect(onChangeMock).toHaveBeenCalledWith({ target: { value: 2 } })
+ );
});
it("Decrease number with button", async () => {
const decreaseButton = getByLabelText(componentContainer, "Decrease");
fireEvent.mouseDown(decreaseButton);
- await wait(() => expect(onChangeMock).toHaveBeenCalledWith({ target: { value: 0 } }));
+ await wait(() =>
+ expect(onChangeMock).toHaveBeenCalledWith({ target: { value: 0 } })
+ );
});
});
diff --git a/src/bootstrap/__tests__/PasswordInput.test.js b/src/bootstrap/__tests__/PasswordInput.test.js
index 3d5381b..370d25d 100644
--- a/src/bootstrap/__tests__/PasswordInput.test.js
+++ b/src/bootstrap/__tests__/PasswordInput.test.js
@@ -18,11 +18,9 @@ describe(" ", () => {
label="Test label"
helpText="Some help text"
value="Some password"
- onChange={() => {
- }}
- />,
+ onChange={() => {}}
+ />
);
- expect(container.firstChild)
- .toMatchSnapshot();
+ expect(container.firstChild).toMatchSnapshot();
});
});
diff --git a/src/bootstrap/__tests__/RadioSet.test.js b/src/bootstrap/__tests__/RadioSet.test.js
index 9339346..bcd6726 100644
--- a/src/bootstrap/__tests__/RadioSet.test.js
+++ b/src/bootstrap/__tests__/RadioSet.test.js
@@ -35,11 +35,9 @@ describe(" ", () => {
value="value"
choices={TEST_CHOICES}
helpText="Some help text"
- onChange={() => {
- }}
- />,
+ onChange={() => {}}
+ />
);
- expect(container.firstChild)
- .toMatchSnapshot();
+ expect(container.firstChild).toMatchSnapshot();
});
});
diff --git a/src/bootstrap/__tests__/Select.test.js b/src/bootstrap/__tests__/Select.test.js
index 1a42cd6..f145e48 100644
--- a/src/bootstrap/__tests__/Select.test.js
+++ b/src/bootstrap/__tests__/Select.test.js
@@ -8,7 +8,10 @@
import React from "react";
import {
- fireEvent, getByDisplayValue, getByText, render,
+ fireEvent,
+ getByDisplayValue,
+ getByText,
+ render,
} from "customTestRender";
import { Select } from "../Select";
@@ -29,29 +32,24 @@ describe(" ", () => {
value="1"
choices={TEST_CHOICES}
helpText="Help text"
-
onChange={onChangeHandler}
- />,
+ />
);
selectContainer = container;
});
it("Test with snapshot.", () => {
- expect(selectContainer)
- .toMatchSnapshot();
+ expect(selectContainer).toMatchSnapshot();
});
it("Test onChange handling.", () => {
const select = getByDisplayValue(selectContainer, "one");
- expect(select.value)
- .toBe("1");
+ expect(select.value).toBe("1");
fireEvent.change(select, { target: { value: "2" } });
const option = getByText(selectContainer, "two");
- expect(onChangeHandler)
- .toBeCalled();
+ expect(onChangeHandler).toBeCalled();
- expect(option.value)
- .toBe("2");
+ expect(option.value).toBe("2");
});
});
diff --git a/src/bootstrap/__tests__/TextInput.test.js b/src/bootstrap/__tests__/TextInput.test.js
index c31899d..0bb4f3c 100644
--- a/src/bootstrap/__tests__/TextInput.test.js
+++ b/src/bootstrap/__tests__/TextInput.test.js
@@ -18,11 +18,9 @@ describe(" ", () => {
label="Test label"
helpText="Some help text"
value="Some text"
- onChange={() => {
- }}
- />,
+ onChange={() => {}}
+ />
);
- expect(container.firstChild)
- .toMatchSnapshot();
+ expect(container.firstChild).toMatchSnapshot();
});
});
diff --git a/src/bootstrap/__tests__/__snapshots__/Button.test.js.snap b/src/bootstrap/__tests__/__snapshots__/Button.test.js.snap
index 1cf1143..db9351b 100644
--- a/src/bootstrap/__tests__/__snapshots__/Button.test.js.snap
+++ b/src/bootstrap/__tests__/__snapshots__/Button.test.js.snap
@@ -5,8 +5,6 @@ exports[` Render button correctly 1`] = `
class="btn btn-primary "
type="button"
>
-
-
Test Button
`;
@@ -16,8 +14,6 @@ exports[` Render button with custom classes 1`] = `
class="btn one two three"
type="button"
>
-
-
Test Button
`;
@@ -33,8 +29,6 @@ exports[` Render button with spinner 1`] = `
role="status"
/>
-
-
Test Button
`;
diff --git a/src/common/RebootButton.js b/src/common/RebootButton.js
index f90620a..b72a06c 100644
--- a/src/common/RebootButton.js
+++ b/src/common/RebootButton.js
@@ -13,9 +13,7 @@ import { API_STATE } from "../api/utils";
import { ForisURLs } from "../utils/forisUrls";
import { Button } from "../bootstrap/Button";
-import {
- Modal, ModalHeader, ModalBody, ModalFooter,
-} from "../bootstrap/Modal";
+import { Modal, ModalHeader, ModalBody, ModalFooter } from "../bootstrap/Modal";
import { useAlert } from "../alertContext/AlertContext";
export function RebootButton(props) {
@@ -38,13 +36,16 @@ export function RebootButton(props) {
return (
<>
-
+
setModalShown(true)}
-
{...props}
>
{_("Reboot")}
@@ -63,10 +64,14 @@ function RebootModal({ shown, setShown, onReboot }) {
return (
- {_("Are you sure you want to restart the router?")}
+
+ {_("Are you sure you want to restart the router?")}
+
setShown(false)}>{_("Cancel")}
- {_("Confirm reboot")}
+
+ {_("Confirm reboot")}
+
);
diff --git a/src/common/WiFiSettings/ResetWiFiSettings.js b/src/common/WiFiSettings/ResetWiFiSettings.js
index b8a0c2c..f04c826 100644
--- a/src/common/WiFiSettings/ResetWiFiSettings.js
+++ b/src/common/WiFiSettings/ResetWiFiSettings.js
@@ -25,11 +25,10 @@ export default function ResetWiFiSettings({ ws, endpoint }) {
useEffect(() => {
const module = "wifi";
- ws.subscribe(module)
- .bind(module, "reset", () => {
- // eslint-disable-next-line no-restricted-globals
- setTimeout(() => location.reload(), 1000);
- });
+ ws.subscribe(module).bind(module, "reset", () => {
+ // eslint-disable-next-line no-restricted-globals
+ setTimeout(() => location.reload(), 1000);
+ });
}, [ws]);
const [postResetResponse, postReset] = useAPIPost(endpoint);
@@ -38,7 +37,10 @@ export default function ResetWiFiSettings({ ws, endpoint }) {
if (postResetResponse.state === API_STATE.ERROR) {
setAlert(_("An error occurred during resetting Wi-Fi settings."));
} else if (postResetResponse.state === API_STATE.SUCCESS) {
- setAlert(_("Wi-Fi settings are set to defaults."), ALERT_TYPES.SUCCESS);
+ setAlert(
+ _("Wi-Fi settings are set to defaults."),
+ ALERT_TYPES.SUCCESS
+ );
}
}, [postResetResponse, setAlert]);
@@ -63,7 +65,6 @@ current Wi-Fi configuration and restore the default values.
forisFormSize
loading={isLoading}
disabled={isLoading}
-
onClick={onReset}
>
{_("Reset Wi-Fi Settings")}
diff --git a/src/common/WiFiSettings/WiFiQRCode.js b/src/common/WiFiSettings/WiFiQRCode.js
index 9b30f12..97d49dd 100644
--- a/src/common/WiFiSettings/WiFiQRCode.js
+++ b/src/common/WiFiSettings/WiFiQRCode.js
@@ -12,7 +12,10 @@ import PropTypes from "prop-types";
import { ForisURLs } from "../../utils/forisUrls";
import { Button } from "../../bootstrap/Button";
import {
- Modal, ModalBody, ModalFooter, ModalHeader,
+ Modal,
+ ModalBody,
+ ModalFooter,
+ ModalHeader,
} from "../../bootstrap/Modal";
import { createAndDownloadPdf, toQRCodeContent } from "./qrCodeHelpers";
@@ -36,11 +39,21 @@ export default function WiFiQRCode({ SSID, password }) {
setModal(true);
}}
>
-
+
- {modal
- ?
- : null}
+ {modal ? (
+
+ ) : null}
>
);
}
@@ -52,9 +65,7 @@ QRCodeModal.propTypes = {
setShown: PropTypes.func.isRequired,
};
-function QRCodeModal({
- shown, setShown, SSID, password,
-}) {
+function QRCodeModal({ shown, setShown, SSID, password }) {
return (
diff --git a/src/common/WiFiSettings/WiFiSettings.js b/src/common/WiFiSettings/WiFiSettings.js
index 9f7fa15..a16d8d7 100644
--- a/src/common/WiFiSettings/WiFiSettings.js
+++ b/src/common/WiFiSettings/WiFiSettings.js
@@ -19,9 +19,7 @@ WiFiSettings.propTypes = {
hasGuestNetwork: PropTypes.bool,
};
-export function WiFiSettings({
- ws, endpoint, resetEndpoint, hasGuestNetwork,
-}) {
+export function WiFiSettings({ ws, endpoint, resetEndpoint, hasGuestNetwork }) {
return (
<>
{
- if (!device.enabled) return {};
+ const formErrors = formData.devices.map((device) => {
+ if (!device.enabled) return {};
- const errors = {};
- if (device.SSID.length > 32) errors.SSID = _("SSID can't be longer than 32 symbols");
- if (device.SSID.length === 0) errors.SSID = _("SSID can't be empty");
+ const errors = {};
+ if (device.SSID.length > 32)
+ errors.SSID = _("SSID can't be longer than 32 symbols");
+ if (device.SSID.length === 0) errors.SSID = _("SSID can't be empty");
- if (device.password.length < 8) errors.password = _("Password must contain at least 8 symbols");
+ if (device.password.length < 8)
+ errors.password = _("Password must contain at least 8 symbols");
- if (!device.guest_wifi.enabled) return errors;
+ if (!device.guest_wifi.enabled) return errors;
- const guest_wifi_errors = {};
- if (device.guest_wifi.SSID.length > 32) guest_wifi_errors.SSID = _("SSID can't be longer than 32 symbols");
- if (device.guest_wifi.SSID.length === 0) guest_wifi_errors.SSID = _("SSID can't be empty");
+ const guest_wifi_errors = {};
+ if (device.guest_wifi.SSID.length > 32)
+ guest_wifi_errors.SSID = _("SSID can't be longer than 32 symbols");
+ if (device.guest_wifi.SSID.length === 0)
+ guest_wifi_errors.SSID = _("SSID can't be empty");
- if (device.guest_wifi.password.length < 8) guest_wifi_errors.password = _("Password must contain at least 8 symbols");
+ if (device.guest_wifi.password.length < 8)
+ guest_wifi_errors.password = _(
+ "Password must contain at least 8 symbols"
+ );
- if (guest_wifi_errors.SSID || guest_wifi_errors.password) {
- errors.guest_wifi = guest_wifi_errors;
- }
- return errors;
- },
- );
+ if (guest_wifi_errors.SSID || guest_wifi_errors.password) {
+ errors.guest_wifi = guest_wifi_errors;
+ }
+ return errors;
+ });
return JSON.stringify(formErrors).match(/\[[{},?]+\]/) ? null : formErrors;
}
diff --git a/src/common/WiFiSettings/__tests__/ResetWiFiSettings.test.js b/src/common/WiFiSettings/__tests__/ResetWiFiSettings.test.js
index 6b5f9ed..c4285dd 100644
--- a/src/common/WiFiSettings/__tests__/ResetWiFiSettings.test.js
+++ b/src/common/WiFiSettings/__tests__/ResetWiFiSettings.test.js
@@ -22,19 +22,34 @@ describe(" ", () => {
let getAllByText;
beforeEach(() => {
- ({ getAllByText } = render( ));
+ ({ getAllByText } = render(
+
+ ));
});
it("should display alert on open ports - success", async () => {
fireEvent.click(getAllByText("Reset Wi-Fi Settings")[1]);
- expect(mockAxios.post).toBeCalledWith(endpoint, undefined, expect.anything());
+ expect(mockAxios.post).toBeCalledWith(
+ endpoint,
+ undefined,
+ expect.anything()
+ );
mockAxios.mockResponse({ data: { foo: "bar" } });
- await wait(() => expect(mockSetAlert).toBeCalledWith("Wi-Fi settings are set to defaults.", ALERT_TYPES.SUCCESS));
+ await wait(() =>
+ expect(mockSetAlert).toBeCalledWith(
+ "Wi-Fi settings are set to defaults.",
+ ALERT_TYPES.SUCCESS
+ )
+ );
});
it("should display alert on open ports - failure", async () => {
fireEvent.click(getAllByText("Reset Wi-Fi Settings")[1]);
mockJSONError();
- await wait(() => expect(mockSetAlert).toBeCalledWith("An error occurred during resetting Wi-Fi settings."));
+ await wait(() =>
+ expect(mockSetAlert).toBeCalledWith(
+ "An error occurred during resetting Wi-Fi settings."
+ )
+ );
});
});
diff --git a/src/common/WiFiSettings/__tests__/__fixtures__/wifiSettings.js b/src/common/WiFiSettings/__tests__/__fixtures__/wifiSettings.js
index 4ee0091..5b45398 100644
--- a/src/common/WiFiSettings/__tests__/__fixtures__/wifiSettings.js
+++ b/src/common/WiFiSettings/__tests__/__fixtures__/wifiSettings.js
@@ -292,11 +292,7 @@ export function wifiSettingsFixture() {
radar: false,
},
],
- available_htmodes: [
- "NOHT",
- "HT20",
- "HT40",
- ],
+ available_htmodes: ["NOHT", "HT20", "HT40"],
hwmode: "11g",
},
],
@@ -327,9 +323,9 @@ const oneDevice = {
htmode: "HT40",
hwmode: "11a",
id: 0,
- password: "TestPass"
- }
- ]
+ password: "TestPass",
+ },
+ ],
};
const twoDevices = {
@@ -343,7 +339,7 @@ const twoDevices = {
htmode: "HT40",
hwmode: "11a",
id: 0,
- password: "TestPass"
+ password: "TestPass",
},
{
SSID: "Turris2",
@@ -354,9 +350,9 @@ const twoDevices = {
htmode: "HT40",
hwmode: "11a",
id: 0,
- password: "TestPass"
- }
- ]
+ password: "TestPass",
+ },
+ ],
};
const threeDevices = {
@@ -370,7 +366,7 @@ const threeDevices = {
htmode: "HT40",
hwmode: "11a",
id: 0,
- password: "TestPass"
+ password: "TestPass",
},
{
SSID: "Turris2",
@@ -381,7 +377,7 @@ const threeDevices = {
htmode: "HT40",
hwmode: "11a",
id: 0,
- password: "TestPass"
+ password: "TestPass",
},
{
SSID: "Turris3",
@@ -392,9 +388,9 @@ const threeDevices = {
htmode: "HT40",
hwmode: "11a",
id: 0,
- password: ""
- }
- ]
+ password: "",
+ },
+ ],
};
-export {oneDevice, twoDevices, threeDevices};
\ No newline at end of file
+export { oneDevice, twoDevices, threeDevices };
diff --git a/src/common/WiFiSettings/constants.js b/src/common/WiFiSettings/constants.js
index 3cc086e..480c505 100644
--- a/src/common/WiFiSettings/constants.js
+++ b/src/common/WiFiSettings/constants.js
@@ -22,7 +22,9 @@ export const HELP_TEXTS = {
password: _(`
WPA2 pre-shared key, that is required to connect to the network.
`),
- hidden: _("If set, network is not visible when scanning for available networks."),
+ hidden: _(
+ "If set, network is not visible when scanning for available networks."
+ ),
hwmode: _(`
The 2.4 GHz band is more widely supported by clients, but tends to have more interference. The 5 GHz band is a
newer standard and may not be supported by all your devices. It usually has less interference, but the signal
diff --git a/src/common/__tests__/RebootButton.test.js b/src/common/__tests__/RebootButton.test.js
index 2d7cc56..c86302a 100644
--- a/src/common/__tests__/RebootButton.test.js
+++ b/src/common/__tests__/RebootButton.test.js
@@ -8,7 +8,11 @@
import React from "react";
import {
- fireEvent, getByText, queryByText, render, wait,
+ fireEvent,
+ getByText,
+ queryByText,
+ render,
+ wait,
} from "customTestRender";
import mockAxios from "jest-mock-axios";
import { mockJSONError } from "testUtils/network";
@@ -19,38 +23,41 @@ import { RebootButton } from "../RebootButton";
describe(" ", () => {
let componentContainer;
beforeEach(() => {
- const { container } = render(<>
-
-
- >);
+ const { container } = render(
+ <>
+
+
+ >
+ );
componentContainer = container;
});
it("Render.", () => {
- expect(componentContainer)
- .toMatchSnapshot();
+ expect(componentContainer).toMatchSnapshot();
});
it("Render modal.", () => {
- expect(queryByText(componentContainer, "Confirm reboot"))
- .toBeNull();
+ expect(queryByText(componentContainer, "Confirm reboot")).toBeNull();
fireEvent.click(getByText(componentContainer, "Reboot"));
- expect(componentContainer)
- .toMatchSnapshot();
+ expect(componentContainer).toMatchSnapshot();
});
it("Confirm reboot.", () => {
fireEvent.click(getByText(componentContainer, "Reboot"));
fireEvent.click(getByText(componentContainer, "Confirm reboot"));
- expect(mockAxios.post)
- .toHaveBeenCalledWith("/reforis/api/reboot", undefined, expect.anything());
+ expect(mockAxios.post).toHaveBeenCalledWith(
+ "/reforis/api/reboot",
+ undefined,
+ expect.anything()
+ );
});
it("Hold error.", async () => {
fireEvent.click(getByText(componentContainer, "Reboot"));
fireEvent.click(getByText(componentContainer, "Confirm reboot"));
mockJSONError();
- await wait(() => expect(mockSetAlert)
- .toBeCalledWith("Reboot request failed."));
+ await wait(() =>
+ expect(mockSetAlert).toBeCalledWith("Reboot request failed.")
+ );
});
});
diff --git a/src/common/__tests__/__snapshots__/RebootButton.test.js.snap b/src/common/__tests__/__snapshots__/RebootButton.test.js.snap
index 80552d4..37279f7 100644
--- a/src/common/__tests__/__snapshots__/RebootButton.test.js.snap
+++ b/src/common/__tests__/__snapshots__/RebootButton.test.js.snap
@@ -49,16 +49,12 @@ exports[` Render modal. 1`] = `
class="btn btn-primary "
type="button"
>
-
-
Cancel
-
-
Confirm reboot
@@ -70,8 +66,6 @@ exports[`
Render modal. 1`] = `
class="btn btn-danger"
type="button"
>
-
-
Reboot
@@ -86,8 +80,6 @@ exports[`
Render. 1`] = `
class="btn btn-danger"
type="button"
>
-
-
Reboot
diff --git a/src/form/__tests__/SubmitButton.test.js b/src/form/__tests__/SubmitButton.test.js
index 593d92e..1f17b24 100644
--- a/src/form/__tests__/SubmitButton.test.js
+++ b/src/form/__tests__/SubmitButton.test.js
@@ -13,17 +13,14 @@ import { STATES, SubmitButton } from "../components/SubmitButton";
describe(" ", () => {
it("Render ready", () => {
const { container } = render( );
- expect(container)
- .toMatchSnapshot();
+ expect(container).toMatchSnapshot();
});
it("Render saving", () => {
const { container } = render( );
- expect(container)
- .toMatchSnapshot();
+ expect(container).toMatchSnapshot();
});
it("Render load", () => {
const { container } = render( );
- expect(container)
- .toMatchSnapshot();
+ expect(container).toMatchSnapshot();
});
});
diff --git a/src/form/__tests__/__snapshots__/SubmitButton.test.js.snap b/src/form/__tests__/__snapshots__/SubmitButton.test.js.snap
index da4df24..c9667b5 100644
--- a/src/form/__tests__/__snapshots__/SubmitButton.test.js.snap
+++ b/src/form/__tests__/__snapshots__/SubmitButton.test.js.snap
@@ -13,8 +13,6 @@ exports[` Render load 1`] = `
role="status"
/>
-
-
Load settings
@@ -26,8 +24,6 @@ exports[` Render ready 1`] = `
class="btn btn-primary col-sm-12 col-md-3 col-lg-2"
type="submit"
>
-
-
Save
@@ -46,8 +42,6 @@ exports[`
Render saving 1`] = `
role="status"
/>
-
-
Updating
diff --git a/src/form/__tests__/hooks.test.js b/src/form/__tests__/hooks.test.js
index 8f69adb..0a2cd04 100644
--- a/src/form/__tests__/hooks.test.js
+++ b/src/form/__tests__/hooks.test.js
@@ -7,9 +7,7 @@
import React from "react";
-import {
- act, fireEvent, render, waitForElement,
-} from "customTestRender";
+import { act, fireEvent, render, waitForElement } from "customTestRender";
import mockAxios from "jest-mock-axios";
import { WebSockets } from "webSockets/WebSockets";
import { ForisForm } from "../components/ForisForm";
@@ -38,8 +36,12 @@ describe("useForm hook.", () => {
beforeEach(async () => {
mockPrepData = jest.fn(() => ({ field: "preparedData" }));
- mockPrepDataToSubmit = jest.fn(() => ({ field: "preparedDataToSubmit" }));
- mockValidator = jest.fn((data) => (data.field === "invalidValue" ? { field: "Error" } : {}));
+ mockPrepDataToSubmit = jest.fn(() => ({
+ field: "preparedDataToSubmit",
+ }));
+ mockValidator = jest.fn((data) =>
+ data.field === "invalidValue" ? { field: "Error" } : {}
+ );
const { getByTestId, container } = render(
{
validator={mockValidator}
>
- ,
+
);
mockAxios.mockResponse({ field: "fetchedData" });
@@ -67,16 +69,22 @@ describe("useForm hook.", () => {
expect(Child.mock.calls[0][0].formErrors).toMatchObject({});
act(() => {
- fireEvent.change(input, { target: { value: "invalidValue", type: "text" } });
+ fireEvent.change(input, {
+ target: { value: "invalidValue", type: "text" },
+ });
});
expect(Child).toHaveBeenCalledTimes(2);
expect(mockValidator).toHaveBeenCalledTimes(2);
- expect(Child.mock.calls[1][0].formErrors).toMatchObject({ field: "Error" });
+ expect(Child.mock.calls[1][0].formErrors).toMatchObject({
+ field: "Error",
+ });
});
it("Update text value.", () => {
- fireEvent.change(input, { target: { value: "newValue", type: "text" } });
+ fireEvent.change(input, {
+ target: { value: "newValue", type: "text" },
+ });
expect(input.value).toBe("newValue");
});
@@ -86,14 +94,21 @@ describe("useForm hook.", () => {
});
it("Update checkbox value.", () => {
- fireEvent.change(input, { target: { checked: true, type: "checkbox" } });
+ fireEvent.change(input, {
+ target: { checked: true, type: "checkbox" },
+ });
expect(input.checked).toBe(true);
});
it("Fetch data.", () => {
- expect(mockAxios.get).toHaveBeenCalledWith("testEndpoint", expect.anything());
+ expect(mockAxios.get).toHaveBeenCalledWith(
+ "testEndpoint",
+ expect.anything()
+ );
expect(mockPrepData).toHaveBeenCalledTimes(1);
- expect(Child.mock.calls[0][0].formData).toMatchObject({ field: "preparedData" });
+ expect(Child.mock.calls[0][0].formData).toMatchObject({
+ field: "preparedData",
+ });
});
it("Submit.", () => {
@@ -107,7 +122,7 @@ describe("useForm hook.", () => {
expect(mockAxios.post).toHaveBeenCalledWith(
"testEndpoint",
{ field: "preparedDataToSubmit" },
- expect.anything(),
+ expect.anything()
);
});
});
diff --git a/src/form/__tests__/validation.test.js b/src/form/__tests__/validation.test.js
index 163d1b9..94de278 100644
--- a/src/form/__tests__/validation.test.js
+++ b/src/form/__tests__/validation.test.js
@@ -16,120 +16,75 @@ import {
describe("Validation functions", () => {
it("validateIPv4Address valid", () => {
- expect(validateIPv4Address("192.168.1.1"))
- .toBe(undefined);
- expect(validateIPv4Address("1.1.1.1"))
- .toBe(undefined);
- expect(validateIPv4Address("0.0.0.0"))
- .toBe(undefined);
+ expect(validateIPv4Address("192.168.1.1")).toBe(undefined);
+ expect(validateIPv4Address("1.1.1.1")).toBe(undefined);
+ expect(validateIPv4Address("0.0.0.0")).toBe(undefined);
});
it("validateIPv4Address invalid", () => {
- expect(validateIPv4Address("invalid"))
- .not
- .toBe(undefined);
- expect(validateIPv4Address("192.256.1.1"))
- .not
- .toBe(undefined);
- expect(validateIPv4Address("192.168.256.1"))
- .not
- .toBe(undefined);
- expect(validateIPv4Address("192.168.1.256"))
- .not
- .toBe(undefined);
- expect(validateIPv4Address("192.168.1.256"))
- .not
- .toBe(undefined);
+ expect(validateIPv4Address("invalid")).not.toBe(undefined);
+ expect(validateIPv4Address("192.256.1.1")).not.toBe(undefined);
+ expect(validateIPv4Address("192.168.256.1")).not.toBe(undefined);
+ expect(validateIPv4Address("192.168.1.256")).not.toBe(undefined);
+ expect(validateIPv4Address("192.168.1.256")).not.toBe(undefined);
});
it("validateIPv6Address valid", () => {
- expect(validateIPv6Address("2001:0db8:85a3:0000:0000:8a2e:0370:7334"))
- .toBe(undefined);
- expect(validateIPv6Address("0:0:0:0:0:0:0:1"))
- .toBe(undefined);
- expect(validateIPv6Address("::1"))
- .toBe(undefined);
- expect(validateIPv6Address("::"))
- .toBe(undefined);
+ expect(
+ validateIPv6Address("2001:0db8:85a3:0000:0000:8a2e:0370:7334")
+ ).toBe(undefined);
+ expect(validateIPv6Address("0:0:0:0:0:0:0:1")).toBe(undefined);
+ expect(validateIPv6Address("::1")).toBe(undefined);
+ expect(validateIPv6Address("::")).toBe(undefined);
});
it("validateIPv6Address invalid", () => {
- expect(validateIPv6Address("invalid"))
- .not
- .toBe(undefined);
- expect(validateIPv6Address("1.1.1.1"))
- .not
- .toBe(undefined);
- expect(validateIPv6Address("1200::AB00:1234::2552:7777:1313"))
- .not
- .toBe(undefined);
- expect(validateIPv6Address("1200:0000:AB00:1234:O000:2552:7777:1313"))
- .not
- .toBe(undefined);
+ expect(validateIPv6Address("invalid")).not.toBe(undefined);
+ expect(validateIPv6Address("1.1.1.1")).not.toBe(undefined);
+ expect(validateIPv6Address("1200::AB00:1234::2552:7777:1313")).not.toBe(
+ undefined
+ );
+ expect(
+ validateIPv6Address("1200:0000:AB00:1234:O000:2552:7777:1313")
+ ).not.toBe(undefined);
});
it("validateIPv6Prefix valid", () => {
- expect(validateIPv6Prefix("2002:0000::/16"))
- .toBe(undefined);
- expect(validateIPv6Prefix("0::/0"))
- .toBe(undefined);
+ expect(validateIPv6Prefix("2002:0000::/16")).toBe(undefined);
+ expect(validateIPv6Prefix("0::/0")).toBe(undefined);
});
it("validateIPv6Prefix invalid", () => {
- expect(validateIPv6Prefix("2001:0db8:85a3:0000:0000:8a2e:0370:7334"))
- .not
- .toBe(undefined);
- expect(validateIPv6Prefix("::1"))
- .not
- .toBe(undefined);
- expect(validateIPv6Prefix("2002:0000::/999"))
- .not
- .toBe(undefined);
+ expect(
+ validateIPv6Prefix("2001:0db8:85a3:0000:0000:8a2e:0370:7334")
+ ).not.toBe(undefined);
+ expect(validateIPv6Prefix("::1")).not.toBe(undefined);
+ expect(validateIPv6Prefix("2002:0000::/999")).not.toBe(undefined);
});
it("validateDomain valid", () => {
- expect(validateDomain("example.com"))
- .toBe(undefined);
- expect(validateDomain("one.two.three"))
- .toBe(undefined);
+ expect(validateDomain("example.com")).toBe(undefined);
+ expect(validateDomain("one.two.three")).toBe(undefined);
});
it("validateDomain invalid", () => {
- expect(validateDomain("test/"))
- .not
- .toBe(undefined);
- expect(validateDomain("."))
- .not
- .toBe(undefined);
+ expect(validateDomain("test/")).not.toBe(undefined);
+ expect(validateDomain(".")).not.toBe(undefined);
});
it("validateDUID valid", () => {
- expect(validateDUID("abcdefAB"))
- .toBe(undefined);
- expect(validateDUID("ABCDEF12"))
- .toBe(undefined);
- expect(validateDUID("ABCDEF12AB"))
- .toBe(undefined);
+ expect(validateDUID("abcdefAB")).toBe(undefined);
+ expect(validateDUID("ABCDEF12")).toBe(undefined);
+ expect(validateDUID("ABCDEF12AB")).toBe(undefined);
});
it("validateDUID invalid", () => {
- expect(validateDUID("gggggggg"))
- .not
- .toBe(undefined);
- expect(validateDUID("abcdefABa"))
- .not
- .toBe(undefined);
+ expect(validateDUID("gggggggg")).not.toBe(undefined);
+ expect(validateDUID("abcdefABa")).not.toBe(undefined);
});
it("validateMAC valid", () => {
- expect(validateMAC("00:D0:56:F2:B5:12"))
- .toBe(undefined);
- expect(validateMAC("00:26:DD:14:C4:EE"))
- .toBe(undefined);
- expect(validateMAC("06:00:00:00:00:00"))
- .toBe(undefined);
+ expect(validateMAC("00:D0:56:F2:B5:12")).toBe(undefined);
+ expect(validateMAC("00:26:DD:14:C4:EE")).toBe(undefined);
+ expect(validateMAC("06:00:00:00:00:00")).toBe(undefined);
});
it("validateMAC invalid", () => {
- expect(validateMAC("00:00:00:00:00:0G"))
- .not
- .toBe(undefined);
- expect(validateMAC("06:00:00:00:00:00:00"))
- .not
- .toBe(undefined);
+ expect(validateMAC("00:00:00:00:00:0G")).not.toBe(undefined);
+ expect(validateMAC("06:00:00:00:00:00:00")).not.toBe(undefined);
});
});
diff --git a/src/form/components/ForisForm.js b/src/form/components/ForisForm.js
index e2cf06e..2887f25 100644
--- a/src/form/components/ForisForm.js
+++ b/src/form/components/ForisForm.js
@@ -52,19 +52,25 @@ ForisForm.propTypes = {
onSubmitOverridden: PropTypes.func,
/** Reference to actual form element (useful for programmatically submitting it).
* Pass the output of useRef hook to this prop.
- */
+ */
formReference: PropTypes.object,
/** reForis form components. */
children: PropTypes.node.isRequired,
// eslint-disable-next-line react/no-unused-prop-types
customWSProp(props) {
- const wsModuleIsSpecified = !!(props.forisConfig && props.forisConfig.wsModule);
+ const wsModuleIsSpecified = !!(
+ props.forisConfig && props.forisConfig.wsModule
+ );
if (props.ws && !wsModuleIsSpecified) {
- return new Error("forisConfig.wsModule should be specified when ws object is passed.");
+ return new Error(
+ "forisConfig.wsModule should be specified when ws object is passed."
+ );
}
if (!props.ws && wsModuleIsSpecified) {
- return new Error("forisConfig.wsModule is specified without passing ws object.");
+ return new Error(
+ "forisConfig.wsModule is specified without passing ws object."
+ );
}
},
};
@@ -95,7 +101,10 @@ export function ForisForm({
formReference,
children,
}) {
- const [formState, onFormChangeHandler, resetFormData] = useForm(validator, prepData);
+ const [formState, onFormChangeHandler, resetFormData] = useForm(
+ validator,
+ prepData
+ );
const [setAlert, dismissAlert] = useAlert();
const [forisModuleState] = useForisModule(ws, forisConfig);
@@ -141,29 +150,39 @@ export function ForisForm({
return SUBMIT_BUTTON_STATES.READY;
}
- const formIsDisabled = (disabled
- || forisModuleState.state === API_STATE.SENDING
- || postState.state === API_STATE.SENDING);
+ const formIsDisabled =
+ disabled ||
+ forisModuleState.state === API_STATE.SENDING ||
+ postState.state === API_STATE.SENDING;
const submitButtonIsDisabled = disabled || !!formState.errors;
- const childrenWithFormProps = React.Children.map(
- children,
- (child) => React.cloneElement(child, {
+ const childrenWithFormProps = React.Children.map(children, (child) =>
+ React.cloneElement(child, {
initialData: formState.initialData,
formData: formState.data,
formErrors: formState.errors,
setFormValue: onFormChangeHandler,
disabled: formIsDisabled,
- }),
+ })
);
const onSubmit = onSubmitOverridden
- ? onSubmitOverridden(formState.data, onFormChangeHandler, onSubmitHandler)
+ ? onSubmitOverridden(
+ formState.data,
+ onFormChangeHandler,
+ onSubmitHandler
+ )
: onSubmitHandler;
function getMessageOnLeavingPage() {
- if (JSON.stringify(formState.data) === JSON.stringify(formState.initialData)) return true;
- return _("Changes you made may not be saved. Are you sure you want to leave?");
+ if (
+ JSON.stringify(formState.data) ===
+ JSON.stringify(formState.initialData)
+ )
+ return true;
+ return _(
+ "Changes you made may not be saved. Are you sure you want to leave?"
+ );
}
return (
diff --git a/src/form/components/ForisForm.md b/src/form/components/ForisForm.md
index c3fa814..c6cdc91 100644
--- a/src/form/components/ForisForm.md
+++ b/src/form/components/ForisForm.md
@@ -1,8 +1,11 @@
-` ` is Higher-Order Component which encapsulates entire form logic and provides with children required props.
-This component structure provides comfort API and allows to create typical Foris module forms easily.
+` ` is Higher-Order Component which encapsulates entire form logic
+and provides with children required props. This component structure provides
+comfort API and allows to create typical Foris module forms easily.
## Example of usage of ` `
+
You can pass more forms as children.
+
```js
({ mac_settings: { custom_mac_enabled: { $set: value } } }),
- )}
-
+ onChange={setFormValue((value) => ({
+ mac_settings: { custom_mac_enabled: { $set: value } },
+ }))}
{...props}
/>
- {macSettings.custom_mac_enabled
- ? (
- ({ mac_settings: { custom_mac: { $set: value } } }),
- )}
-
- {...props}
- />
- )
- : null}
+ {macSettings.custom_mac_enabled ? (
+ ({
+ mac_settings: { custom_mac: { $set: value } },
+ }))}
+ {...props}
+ />
+ ) : null}
>
);
}
```
+
The passes subsequent `props` to the child components.
| Prop | Type | Description |
-|----------------|--------|----------------------------------------------------------------------------|
+| -------------- | ------ | -------------------------------------------------------------------------- |
| `formData` | object | Data returned from API. |
| `formErrors` | object | Errors returned after validation via validator. |
| `setFormValue` | func | Function for data update. It takes update rule as arg (see example above). |
diff --git a/src/form/components/SubmitButton.js b/src/form/components/SubmitButton.js
index a5a1f64..1f4f150 100644
--- a/src/form/components/SubmitButton.js
+++ b/src/form/components/SubmitButton.js
@@ -18,8 +18,7 @@ export const STATES = {
SubmitButton.propTypes = {
disabled: PropTypes.bool,
- state: PropTypes.oneOf(Object.keys(STATES)
- .map((key) => STATES[key])),
+ state: PropTypes.oneOf(Object.keys(STATES).map((key) => STATES[key])),
};
export function SubmitButton({ disabled, state, ...props }) {
@@ -28,14 +27,14 @@ export function SubmitButton({ disabled, state, ...props }) {
let labelSubmitButton;
switch (state) {
- case STATES.SAVING:
- labelSubmitButton = _("Updating");
- break;
- case STATES.LOAD:
- labelSubmitButton = _("Load settings");
- break;
- default:
- labelSubmitButton = _("Save");
+ case STATES.SAVING:
+ labelSubmitButton = _("Updating");
+ break;
+ case STATES.LOAD:
+ labelSubmitButton = _("Load settings");
+ break;
+ default:
+ labelSubmitButton = _("Save");
}
return (
@@ -44,7 +43,6 @@ export function SubmitButton({ disabled, state, ...props }) {
loading={loadingSubmitButton}
disabled={disableSubmitButton}
forisFormSize
-
{...props}
>
{labelSubmitButton}
diff --git a/src/form/hooks.js b/src/form/hooks.js
index e0e5824..23c436a 100644
--- a/src/form/hooks.js
+++ b/src/form/hooks.js
@@ -23,57 +23,61 @@ export function useForm(validator, dataPreprocessor) {
errors: {},
});
- const onFormReload = useCallback((data) => {
- dispatch({
- type: FORM_ACTIONS.resetData,
- data,
- dataPreprocessor,
- validator,
- });
- }, [dataPreprocessor, validator]);
+ const onFormReload = useCallback(
+ (data) => {
+ dispatch({
+ type: FORM_ACTIONS.resetData,
+ data,
+ dataPreprocessor,
+ validator,
+ });
+ },
+ [dataPreprocessor, validator]
+ );
- const onFormChangeHandler = useCallback((updateRule) => (event) => {
- dispatch({
- type: FORM_ACTIONS.updateValue,
- value: getChangedValue(event.target),
- updateRule,
- validator,
- });
- }, [validator]);
+ const onFormChangeHandler = useCallback(
+ (updateRule) => (event) => {
+ dispatch({
+ type: FORM_ACTIONS.updateValue,
+ value: getChangedValue(event.target),
+ updateRule,
+ validator,
+ });
+ },
+ [validator]
+ );
- return [
- state,
- onFormChangeHandler,
- onFormReload,
- ];
+ return [state, onFormChangeHandler, onFormReload];
}
function formReducer(state, action) {
switch (action.type) {
- case FORM_ACTIONS.updateValue: {
- const newData = update(state.data, action.updateRule(action.value));
- const errors = action.validator(newData);
- return {
- ...state,
- data: newData,
- errors,
- };
- }
- case FORM_ACTIONS.resetData: {
- if (!action.data) {
- return { ...state, initialData: state.data };
+ case FORM_ACTIONS.updateValue: {
+ const newData = update(state.data, action.updateRule(action.value));
+ const errors = action.validator(newData);
+ return {
+ ...state,
+ data: newData,
+ errors,
+ };
}
+ case FORM_ACTIONS.resetData: {
+ if (!action.data) {
+ return { ...state, initialData: state.data };
+ }
- const data = action.dataPreprocessor ? action.dataPreprocessor(action.data) : action.data;
- return {
- data,
- initialData: data,
- errors: action.data ? action.validator(data) : undefined,
- };
- }
- default: {
- throw new Error();
- }
+ const data = action.dataPreprocessor
+ ? action.dataPreprocessor(action.data)
+ : action.data;
+ return {
+ data,
+ initialData: data,
+ errors: action.data ? action.validator(data) : undefined,
+ };
+ }
+ default: {
+ throw new Error();
+ }
}
}
diff --git a/src/testUtils/alertContextMock.js b/src/testUtils/alertContextMock.js
index b1f6b81..9cb7a8c 100644
--- a/src/testUtils/alertContextMock.js
+++ b/src/testUtils/alertContextMock.js
@@ -15,7 +15,7 @@ window.AlertContext = React.createContext();
function AlertContextMock({ children }) {
return (
- { children }
+ {children}
);
}
diff --git a/src/testUtils/customTestRender.js b/src/testUtils/customTestRender.js
index 2f55854..8d41a60 100644
--- a/src/testUtils/customTestRender.js
+++ b/src/testUtils/customTestRender.js
@@ -26,15 +26,14 @@ function Wrapper({ children }) {
return (
-
- {children}
-
+ {children}
);
}
-const customTestRender = (ui, options) => render(ui, { wrapper: Wrapper, ...options });
+const customTestRender = (ui, options) =>
+ render(ui, { wrapper: Wrapper, ...options });
// re-export everything
export * from "@testing-library/react";
diff --git a/src/testUtils/network.js b/src/testUtils/network.js
index b7473d3..642b3af 100644
--- a/src/testUtils/network.js
+++ b/src/testUtils/network.js
@@ -8,5 +8,7 @@
import mockAxios from "jest-mock-axios";
export function mockJSONError(data) {
- mockAxios.mockError({ response: { data, headers: { "content-type": "application/json" } } });
+ mockAxios.mockError({
+ response: { data, headers: { "content-type": "application/json" } },
+ });
}
diff --git a/src/utils/ErrorMessage.js b/src/utils/ErrorMessage.js
index 77b79ec..acb5c97 100644
--- a/src/utils/ErrorMessage.js
+++ b/src/utils/ErrorMessage.js
@@ -17,7 +17,5 @@ ErrorMessage.defaultProps = {
};
export function ErrorMessage({ message }) {
- return (
- {message}
- );
+ return {message}
;
}
diff --git a/src/utils/__tests__/conditionalHOCs.test.js b/src/utils/__tests__/conditionalHOCs.test.js
index eab07d1..a9ca474 100644
--- a/src/utils/__tests__/conditionalHOCs.test.js
+++ b/src/utils/__tests__/conditionalHOCs.test.js
@@ -9,7 +9,12 @@ import React from "react";
import { render } from "customTestRender";
import { API_STATE } from "api/utils";
import {
- withEither, withSpinner, withSending, withSpinnerOnSending, withError, withErrorMessage,
+ withEither,
+ withSpinner,
+ withSending,
+ withSpinnerOnSending,
+ withError,
+ withErrorMessage,
} from "../conditionalHOCs";
describe("conditional HOCs", () => {
@@ -52,14 +57,18 @@ describe("conditional HOCs", () => {
it("should render First component", () => {
const withAlternative = withSending(Alternative);
const FirstWithConditional = withAlternative(First);
- const { getByText } = render( );
+ const { getByText } = render(
+
+ );
expect(getByText("First")).toBeDefined();
});
it("should render Alternative component", () => {
const withAlternative = withSending(Alternative);
const FirstWithConditional = withAlternative(First);
- const { getByText } = render( );
+ const { getByText } = render(
+
+ );
expect(getByText("Alternative")).toBeDefined();
});
});
@@ -67,13 +76,17 @@ describe("conditional HOCs", () => {
describe("withSpinnerOnSending", () => {
it("should render First component", () => {
const FirstWithConditional = withSpinnerOnSending(First);
- const { getByText } = render( );
+ const { getByText } = render(
+
+ );
expect(getByText("First")).toBeDefined();
});
it("should render spinner", () => {
const FirstWithConditional = withSpinnerOnSending(First);
- const { container } = render( );
+ const { container } = render(
+
+ );
expect(container).toMatchSnapshot();
});
});
@@ -97,13 +110,17 @@ describe("conditional HOCs", () => {
describe("withErrorMessage", () => {
it("should render First component", () => {
const FirstWithConditional = withErrorMessage(First);
- const { getByText } = render( );
+ const { getByText } = render(
+
+ );
expect(getByText("First")).toBeDefined();
});
it("should render error message", () => {
const FirstWithConditional = withErrorMessage(First);
- const { container } = render( );
+ const { container } = render(
+
+ );
expect(container).toMatchSnapshot();
});
});
diff --git a/src/utils/__tests__/datetime.test.js b/src/utils/__tests__/datetime.test.js
index b59478a..3d4b760 100644
--- a/src/utils/__tests__/datetime.test.js
+++ b/src/utils/__tests__/datetime.test.js
@@ -10,42 +10,40 @@ import { toLocaleDateString } from "../datetime";
describe("toLocaleDateString", () => {
it("should work with different locale", () => {
global.ForisTranslations = { locale: "fr" };
- expect(
- toLocaleDateString("2020-02-20T12:51:36+00:00")
- ).toBe("20 février 2020 12:51");
+ expect(toLocaleDateString("2020-02-20T12:51:36+00:00")).toBe(
+ "20 février 2020 12:51"
+ );
global.ForisTranslations = { locale: "en" };
- })
+ });
it("should convert with default format", () => {
- expect(
- toLocaleDateString("2020-02-20T12:51:36+00:00")
- ).toBe("February 20, 2020 12:51 PM");
+ expect(toLocaleDateString("2020-02-20T12:51:36+00:00")).toBe(
+ "February 20, 2020 12:51 PM"
+ );
});
it("should convert with custom input format", () => {
expect(
- toLocaleDateString(
- "2020-02-20 12:51:36 +0000",
- { inputFormat: "YYYY-MM-DD HH:mm:ss Z" },
- )
+ toLocaleDateString("2020-02-20 12:51:36 +0000", {
+ inputFormat: "YYYY-MM-DD HH:mm:ss Z",
+ })
).toBe("February 20, 2020 12:51 PM");
});
it("should convert with custom output format", () => {
expect(
- toLocaleDateString(
- "2020-02-20T12:51:36+00:00",
- { outputFormat: "LL" },
- )
+ toLocaleDateString("2020-02-20T12:51:36+00:00", {
+ outputFormat: "LL",
+ })
).toBe("February 20, 2020");
});
it("should convert with custom input and output format", () => {
expect(
- toLocaleDateString(
- "2020-02-20 12:51:36 +0000",
- { inputFormat: "YYYY-MM-DD HH:mm:ss Z", outputFormat: "LL" },
- )
+ toLocaleDateString("2020-02-20 12:51:36 +0000", {
+ inputFormat: "YYYY-MM-DD HH:mm:ss Z",
+ outputFormat: "LL",
+ })
).toBe("February 20, 2020");
});
});
diff --git a/src/utils/conditionalHOCs.js b/src/utils/conditionalHOCs.js
index 5f39920..3298f81 100644
--- a/src/utils/conditionalHOCs.js
+++ b/src/utils/conditionalHOCs.js
@@ -24,8 +24,8 @@ function withEither(conditionalFn, Either) {
function isSending(props) {
if (Array.isArray(props.apiState)) {
- return props.apiState.some(
- (state) => [API_STATE.INIT, API_STATE.SENDING].includes(state),
+ return props.apiState.some((state) =>
+ [API_STATE.INIT, API_STATE.SENDING].includes(state)
);
}
return [API_STATE.INIT, API_STATE.SENDING].includes(props.apiState);
@@ -38,15 +38,18 @@ const withSpinnerOnSending = withSpinner(isSending);
// Error handling
const withError = (conditionalFn) => withEither(conditionalFn, ErrorMessage);
-const withErrorMessage = withError(
- (props) => {
- if (Array.isArray(props.apiState)) {
- return props.apiState.includes(API_STATE.ERROR);
- }
- return props.apiState === API_STATE.ERROR;
- },
-);
+const withErrorMessage = withError((props) => {
+ if (Array.isArray(props.apiState)) {
+ return props.apiState.includes(API_STATE.ERROR);
+ }
+ return props.apiState === API_STATE.ERROR;
+});
export {
- withEither, withSpinner, withSending, withSpinnerOnSending, withError, withErrorMessage,
+ withEither,
+ withSpinner,
+ withSending,
+ withSpinnerOnSending,
+ withError,
+ withErrorMessage,
};
diff --git a/src/utils/datetime.js b/src/utils/datetime.js
index f7e30b8..7190167 100644
--- a/src/utils/datetime.js
+++ b/src/utils/datetime.js
@@ -1,8 +1,9 @@
import moment from "moment";
-export function toLocaleDateString(date, { inputFormat, outputFormat = "LLL" } = {}) {
+export function toLocaleDateString(
+ date,
+ { inputFormat, outputFormat = "LLL" } = {}
+) {
const parsedDate = inputFormat ? moment(date, inputFormat) : moment(date);
- return parsedDate
- .locale(ForisTranslations.locale)
- .format(outputFormat);
+ return parsedDate.locale(ForisTranslations.locale).format(outputFormat);
}
diff --git a/src/utils/hooks.js b/src/utils/hooks.js
index d43c2b8..e554a9d 100644
--- a/src/utils/hooks.js
+++ b/src/utils/hooks.js
@@ -8,11 +8,17 @@
import { useState, useEffect } from "react";
/** Execute callback when condition is set to true. */
-export function useConditionalTimeout({ callback, timeout = 125 }, ...callbackArgs) {
+export function useConditionalTimeout(
+ { callback, timeout = 125 },
+ ...callbackArgs
+) {
const [condition, setCondition] = useState(false);
useEffect(() => {
if (condition) {
- const interval = setTimeout(() => callback(...callbackArgs), timeout);
+ const interval = setTimeout(
+ () => callback(...callbackArgs),
+ timeout
+ );
return () => setTimeout(interval);
}
}, [condition, callback, timeout, callbackArgs]);
diff --git a/src/utils/objectHelpers.js b/src/utils/objectHelpers.js
index a26177a..068d738 100644
--- a/src/utils/objectHelpers.js
+++ b/src/utils/objectHelpers.js
@@ -15,21 +15,18 @@ export function undefinedIfEmpty(instance) {
/** Return object without keys that have undefined value. */
export function withoutUndefinedKeys(instance) {
- return Object.keys(instance).reduce(
- (accumulator, key) => {
- if (instance[key] !== undefined) {
- accumulator[key] = instance[key];
- }
- return accumulator;
- },
- {},
- );
+ return Object.keys(instance).reduce((accumulator, key) => {
+ if (instance[key] !== undefined) {
+ accumulator[key] = instance[key];
+ }
+ return accumulator;
+ }, {});
}
/** Return copy of passed object that has only desired keys. */
export function onlySpecifiedKeys(object, desiredKeys) {
- return desiredKeys.reduce(
- (accumulator, key) => { accumulator[key] = object[key]; return accumulator; },
- {},
- );
+ return desiredKeys.reduce((accumulator, key) => {
+ accumulator[key] = object[key];
+ return accumulator;
+ }, {});
}
diff --git a/src/utils/validations.js b/src/utils/validations.js
index dc38ff9..12671df 100644
--- a/src/utils/validations.js
+++ b/src/utils/validations.js
@@ -30,7 +30,10 @@ const REs = {
};
const createValidator = (fieldType) => (value) => {
- if (value && value !== "") return REs[fieldType].test(value) ? undefined : ERROR_MESSAGES[fieldType];
+ if (value && value !== "")
+ return REs[fieldType].test(value)
+ ? undefined
+ : ERROR_MESSAGES[fieldType];
};
const validateIPv4Address = createValidator("IPv4");
diff --git a/src/webSockets/WebSockets.js b/src/webSockets/WebSockets.js
index ec33a49..5663948 100644
--- a/src/webSockets/WebSockets.js
+++ b/src/webSockets/WebSockets.js
@@ -22,7 +22,9 @@ export class WebSockets {
this.ws = new WebSocket(URL);
this.ws.onerror = (e) => {
if (window.location.pathname !== ForisURLs.login) {
- console.error("WS: Error observed, you aren't logged probably.");
+ console.error(
+ "WS: Error observed, you aren't logged probably."
+ );
window.location.replace(ForisURLs.login);
}
console.error(`WS: Error: ${e}`);
@@ -111,7 +113,9 @@ export class WebSockets {
chain = this.callbacks[json.module][json.action];
} catch (error) {
if (error instanceof TypeError) {
- console.warn(`Callback for this message wasn't found:${error.data}`);
+ console.warn(
+ `Callback for this message wasn't found:${error.data}`
+ );
} else throw error;
}
diff --git a/src/webSockets/hooks.js b/src/webSockets/hooks.js
index 44f7e09..fcaa4f8 100644
--- a/src/webSockets/hooks.js
+++ b/src/webSockets/hooks.js
@@ -7,7 +7,12 @@
import { useEffect, useState } from "react";
-export function useWSForisModule(ws, module, action = "update_settings", controllerID) {
+export function useWSForisModule(
+ ws,
+ module,
+ action = "update_settings",
+ controllerID
+) {
const [data, setData] = useState(null);
useEffect(() => {
@@ -18,14 +23,16 @@ export function useWSForisModule(ws, module, action = "update_settings", control
function callback(message) {
// Accept only messages addressed to device with passed controller ID.
- if (controllerID !== undefined && controllerID !== message.controller_id) {
+ if (
+ controllerID !== undefined &&
+ controllerID !== message.controller_id
+ ) {
return;
}
setData(message.data);
}
- ws.subscribe(module)
- .bind(module, action, callback);
+ ws.subscribe(module).bind(module, action, callback);
return () => {
ws.unbind(module, action, callback);
diff --git a/styleguide.config.js b/styleguide.config.js
index e54594f..295c93a 100644
--- a/styleguide.config.js
+++ b/styleguide.config.js
@@ -30,9 +30,7 @@ module.exports = {
},
{
name: "Alert Context",
- components: [
- "src/alertContext/AlertContext.js",
- ],
+ components: ["src/alertContext/AlertContext.js"],
exampleMode: "expand",
usageMode: "expand",
},
@@ -42,16 +40,20 @@ module.exports = {
components: "src/bootstrap/*.js",
exampleMode: "expand",
usageMode: "expand",
- ignore: [
- "src/bootstrap/constants.js",
- ],
+ ignore: ["src/bootstrap/constants.js"],
},
],
require: [
"babel-polyfill",
path.join(__dirname, "src/testUtils/mockGlobals"),
- path.join(__dirname, "node_modules/bootstrap/dist/css/bootstrap.min.css"),
- path.join(__dirname, "node_modules/@fortawesome/fontawesome-free/css/all.min.css"),
+ path.join(
+ __dirname,
+ "node_modules/bootstrap/dist/css/bootstrap.min.css"
+ ),
+ path.join(
+ __dirname,
+ "node_modules/@fortawesome/fontawesome-free/css/all.min.css"
+ ),
],
webpackConfig: {
module: {
@@ -60,10 +62,12 @@ module.exports = {
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
- }, {
+ },
+ {
test: /\.css$/,
use: ["style-loader", "css-loader"],
- }, {
+ },
+ {
test: /\.(jpg|jpeg|png|woff|woff2|eot|ttf|svg)$/,
loader: "file-loader",
},