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 ; -}; - + return ( + setAlert(false)}> + Some warning out there! + + ); + return ( + + ); +} +; ``` 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 - ?
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 `
`. +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 ``. All additional `props` are passed to the `` HTML component. ```js -import {useState} from 'react'; -const [email, setEmail] = useState('Wrong email'); -e.preventDefault()}> +import { useState } from "react"; +const [email, setEmail] = useState("Wrong email"); + e.preventDefault()}> setEmail(event.target.value)} + onChange={(event) => setEmail(event.target.value)} /> - +; ``` 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";
setFiles(event.target.files)} + onChange={(event) => setFiles(event.target.files)} multiple /> - +; ``` 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 (
- +
{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}
-
@@ -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 -