1
0
mirror of https://gitlab.nic.cz/turris/reforis/foris-js.git synced 2025-06-16 13:46:16 +02:00

Compare commits

..

1 Commits

Author SHA1 Message Date
02671fb645 Merge branch 'dev' into 'master'
Dev

See merge request turris/reforis/foris-js!278
2025-04-04 16:06:46 +02:00
28 changed files with 13997 additions and 345 deletions

View File

@ -8,24 +8,6 @@ and this project adheres to
## [Unreleased] ## [Unreleased]
## [6.7.2] - 2025-04-22
### Added
- Added Turris logo to enhanced QR code display
### Changed
- Replaced deprecated QRCode component with QRCodeSVG
- Refactored button click handlers to simplify event handling in WiFiQRCode
- Re-resolved and re-locked all npm dependencies in package-lock.json
- Overridden markdown-to-jsx version in order to solve audit issues
- docs: Enhanced styleguide configuration with new font and layout options
- docs: Refactored development and introduction sections
- docs: Fixed code snippets syntax highlighting & some refactoring
- docs: Updated SubmitButton component
- NPM audit fix
## [6.7.1] - 2025-04-04 ## [6.7.1] - 2025-04-04
### Added ### Added
@ -486,8 +468,7 @@ and this project adheres to
## [0.0.7] - 2019-09-02 ## [0.0.7] - 2019-09-02
[unreleased]: [unreleased]:
https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.7.2...dev https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.7.1...dev
[6.7.2]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.7.1...v6.7.2
[6.7.1]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.7.0...v6.7.1 [6.7.1]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.7.0...v6.7.1
[6.7.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.6.2...v6.7.0 [6.7.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.6.2...v6.7.0
[6.6.2]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.6.1...v6.6.2 [6.6.2]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.6.1...v6.6.2

View File

@ -1,27 +1,25 @@
At some point, you'll likely need to modify the library. When that happens, your Sooner or later, you will face with situation when you want/need to make some
best friend will be [`npm link`](https://docs.npmjs.com/cli/link). changes in the library. Then the most important tool for you it's the
[`npm link`](https://docs.npmjs.com/cli/link).
**Important Note:** Simply linking from the repo root won't work because the Please, notice that it will not work if you link the library just from the root
source files are in `./src`. Instead, you'll need to: of the repo. It happens due to the location of sources `./src`. You need to pack
the library first, `make pack` and then link it from the `./dist` directory.
1. First package the library using `make pack` Yeah, it's not such a comfortable solution for development. But it can be fixed
2. Then link it from the `./dist` directory by writing a small script similar to making a pack but by linking every file and
directory from `./src` to the same directory and linking then from it. Notice
that you need to link a `package.json` and a `package-lock.json` as well.
While this isn't the most developer-friendly workflow, you can improve it by So step by step:
creating a script that:
- Symlinks all files/directories from `./src` to another location
- Also links `package.json` and `package-lock.json`
## Quick Start Guide
```bash ```bash
# Package and link the library make pack;
make pack cd dist;
cd dist npm link;
npm link
# Link to your project cd $project_dir/js # Navigate to JS directory of the project where you want to link the library
cd /path/to/your/project/js # Navigate to your project's JS directory
npm link foris npm link foris
``` ```
And that's it ;)

View File

@ -1,37 +1,35 @@
Welcome to the official Foris JS documentation! Welcome! This is the official documentation for Foris JS.
## About Foris JS ## What Foris JS is
Foris JS is a library containing reusable components and utilities designed Foris JS library is a set of components and utils for reForis application and
specifically for the reForis application and its plugins. plugins.
**Note:** All components and utilities in this library are actively used in Please notice that all of these components or utils are used in reForis and
reForis and its plugins. To see practical examples of how they're implemented, plugins. If you want to study them by example, I recommend you to full-text
we recommend searching through those repositories. search those repositories.
## Getting Started # Installation
### Prerequisites ## Prerequisites
Before installing, ensure you have [Node.js](https://nodejs.org/en/) installed Please make sure that [Node.js](https://nodejs.org/en/) is installed on your
on your system. system.
We recommend using the current Long Term Support (LTS) version for optimal The current Long Term Support (LTS) release is an ideal starting point, see
compatibility. Check the [here](https://github.com/nodejs/Release#release-schedule).
[release schedule](https://github.com/nodejs/Release#release-schedule) for
details.
### Installation ## Installation
Install the latest version with: To install the latest release:
```bash ```plain
npm install foris npm install foris
``` ```
Or install a specific version by running: To install a specific version:
```bash ```plain
npm install foris@version npm install foris@version
``` ```

13808
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "foris", "name": "foris",
"version": "6.7.2", "version": "6.7.1",
"description": "Foris JS library is a set of components and utils for reForis application and plugins.", "description": "Foris JS library is a set of components and utils for reForis application and plugins.",
"author": "CZ.NIC, z.s.p.o.", "author": "CZ.NIC, z.s.p.o.",
"repository": { "repository": {
@ -62,9 +62,6 @@
"style-loader": "^4.0.0", "style-loader": "^4.0.0",
"webpack": "^5.98.0" "webpack": "^5.98.0"
}, },
"overrides": {
"markdown-to-jsx": "^7.7.4"
},
"scripts": { "scripts": {
"lint": "eslint src", "lint": "eslint src",
"lint:fix": "eslint --fix src", "lint:fix": "eslint --fix src",

View File

@ -4,7 +4,7 @@ using in foris forms.
All additional `props` are passed to the `<input type="checkbox">` HTML All additional `props` are passed to the `<input type="checkbox">` HTML
component. component.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
const [value, setValue] = useState(false); const [value, setValue] = useState(false);

View File

@ -4,7 +4,7 @@ be used with `readOnly` and `disabled` parameters, please see an example.
All additional `props` are passed to the `<input type="text">` HTML component. All additional `props` are passed to the `<input type="text">` HTML component.
```jsx ```js
import React, { useState } from "react"; import React, { useState } from "react";
const [value, setValue] = useState("Text to appear in clipboard."); const [value, setValue] = useState("Text to appear in clipboard.");

View File

@ -4,7 +4,7 @@ Adopted from `react-datetime/DateTime` datatime picker component. It uses
It requires `ForisTranslations.locale` to be defined in order to use right It requires `ForisTranslations.locale` to be defined in order to use right
locale. locale.
```jsx ```js
ForisTranslations = { locale: "en" }; ForisTranslations = { locale: "en" };
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";

View File

@ -5,6 +5,6 @@ Firefox. See
[related issue](https://bugzilla.mozilla.org/show_bug.cgi?id=858538) for more [related issue](https://bugzilla.mozilla.org/show_bug.cgi?id=858538) for more
details. details.
```jsx ```js
<DownloadButton href="example.zip">Download</DownloadButton> <DownloadButton href="example.zip">Download</DownloadButton>
``` ```

View File

@ -4,12 +4,10 @@ checking. It's only meaningful using inside `<form>`.
All additional `props` are passed to the `<input type="email">` HTML component. All additional `props` are passed to the `<input type="email">` HTML component.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
import Button from "./Button"; import Button from "./Button";
const [email, setEmail] = useState("Wrong email"); const [email, setEmail] = useState("Wrong email");
<form onSubmit={(e) => e.preventDefault()}> <form onSubmit={(e) => e.preventDefault()}>
<EmailInput <EmailInput
value={email} value={email}

View File

@ -3,7 +3,7 @@ structure for using in foris forms.
All additional `props` are passed to the `<input type="file">` HTML component. All additional `props` are passed to the `<input type="file">` HTML component.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
const [files, setFiles] = useState([]); const [files, setFiles] = useState([]);
@ -23,7 +23,7 @@ const label = files.length === 1 ? files[0].name : "Choose file";
### FileInput with multiple files ### FileInput with multiple files
```jsx ```js
import { useState } from "react"; import { useState } from "react";
const [files, setFiles] = useState([]); const [files, setFiles] = useState([]);

View File

@ -18,7 +18,7 @@ documentation</a>.
<div id="modal-container" /> <div id="modal-container" />
``` ```
```jsx ```js
import { ModalHeader, ModalBody, ModalFooter } from "./Modal"; import { ModalHeader, ModalBody, ModalFooter } from "./Modal";
import { useState } from "react"; import { useState } from "react";

View File

@ -3,9 +3,8 @@ structure for using in foris forms.
All additional `props` are passed to the `<input type="number">` HTML component. All additional `props` are passed to the `<input type="number">` HTML component.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
const [value, setValue] = useState(42); const [value, setValue] = useState(42);
<NumberInput <NumberInput

View File

@ -4,7 +4,7 @@ for using in foris forms. Can be used with "eye" button, see example.
All additional `props` are passed to the `<input type="password">` HTML All additional `props` are passed to the `<input type="password">` HTML
component. component.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
const [value, setValue] = useState("secret"); const [value, setValue] = useState("secret");

View File

@ -5,9 +5,8 @@ All additional `props` are passed to the `<input type="number">` HTML component.
Unless `helpText` is set for one of the options they are displayed inline. Unless `helpText` is set for one of the options they are displayed inline.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
const CHOICES = [ const CHOICES = [
{ value: "one", label: "1" }, { value: "one", label: "1" },
{ value: "two", label: "2" }, { value: "two", label: "2" },

View File

@ -3,9 +3,8 @@ and structure for using in foris forms.
All additional `props` are passed to the `<select>` HTML component. All additional `props` are passed to the `<select>` HTML component.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
const CHOICES = { const CHOICES = {
apple: "Apple", apple: "Apple",
banana: "Banana", banana: "Banana",

View File

@ -1,5 +1,5 @@
Spiner Bootstrap component. Spiner Bootstrap component.
```jsx ```js
<Spinner>You can put text inside or any component you wish.</Spinner> <Spinner>You can put text inside or any component you wish.</Spinner>
``` ```

View File

@ -1,5 +1,5 @@
Switch example: Switch example:
```jsx ```js
<Switch label="Enable Switch" helpText="Toggle that switch!" /> <Switch label="Enable Switch" helpText="Toggle that switch!" />
``` ```

View File

@ -3,9 +3,8 @@ using in foris forms.
All additional `props` are passed to the `<input type="text">` HTML component. All additional `props` are passed to the `<input type="text">` HTML component.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
const [value, setValue] = useState("Bla bla"); const [value, setValue] = useState("Bla bla");
<TextInput <TextInput

View File

@ -2,7 +2,7 @@ ThreeDotsMenu Bootstrap component is a dropdown menu that appears when the user
clicks on three dots. It is used to display a list of actions that can be clicks on three dots. It is used to display a list of actions that can be
performed on a particular item. performed on a particular item.
```jsx ```js
import { useState } from "react"; import { useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEdit, faTrash } from "@fortawesome/free-solid-svg-icons"; import { faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";

View File

@ -10,8 +10,126 @@ the table component, such as:
### Example ### Example
```jsx ```js
import { columns, data } from "./mockData"; import RichTable from "./RichTable";
const columns = [
{
header: "Name",
accessorKey: "name",
},
{
header: "Surname",
accessorKey: "surname",
},
{
header: "Age",
accessorKey: "age",
},
{
header: "Phone",
accessorKey: "phone",
},
];
const data = [
{
name: "John",
surname: "Coltrane",
age: 30,
phone: "123456789",
},
{
name: "Jane",
surname: "Doe",
age: 25,
phone: "987654321",
},
{
name: "Alice",
surname: "Smith",
age: 35,
phone: "123456789",
},
{
name: "Bob",
surname: "Smith",
age: 40,
phone: "987654321",
},
{
name: "Charlie",
surname: "Brown",
age: 45,
phone: "123456789",
},
{
name: "Daisy",
surname: "Brown",
age: 50,
phone: "987654321",
},
{
name: "Eve",
surname: "Johnson",
age: 55,
phone: "123456789",
},
{
name: "Frank",
surname: "Johnson",
age: 60,
phone: "987654321",
},
{
name: "Grace",
surname: "Williams",
age: 65,
phone: "123456789",
},
{
name: "Henry",
surname: "Williams",
age: 70,
phone: "987654321",
},
{
name: "Ivy",
surname: "Brown",
age: 75,
phone: "123456789",
},
{
name: "Jack",
surname: "Brown",
age: 80,
phone: "987654321",
},
{
name: "Kelly",
surname: "Johnson",
age: 85,
phone: "123456789",
},
{
name: "Liam",
surname: "Johnson",
age: 90,
phone: "987654321",
},
{
name: "Mia",
surname: "Williams",
age: 95,
phone: "123456789",
},
{
name: "Nathan",
surname: "Williams",
age: 100,
phone: "987654321",
},
];
<RichTable columns={columns} data={data} withPagination />; <RichTable columns={columns} data={data} withPagination />;
``` ```

View File

@ -1,119 +0,0 @@
const columns = [
{
header: "Name",
accessorKey: "name",
},
{
header: "Surname",
accessorKey: "surname",
},
{
header: "Age",
accessorKey: "age",
},
{
header: "Phone",
accessorKey: "phone",
},
];
const data = [
{
name: "John",
surname: "Coltrane",
age: 30,
phone: "123456789",
},
{
name: "Jane",
surname: "Doe",
age: 25,
phone: "987654321",
},
{
name: "Alice",
surname: "Smith",
age: 35,
phone: "123456789",
},
{
name: "Bob",
surname: "Smith",
age: 40,
phone: "987654321",
},
{
name: "Charlie",
surname: "Brown",
age: 45,
phone: "123456789",
},
{
name: "Daisy",
surname: "Brown",
age: 50,
phone: "987654321",
},
{
name: "Eve",
surname: "Johnson",
age: 55,
phone: "123456789",
},
{
name: "Frank",
surname: "Johnson",
age: 60,
phone: "987654321",
},
{
name: "Grace",
surname: "Williams",
age: 65,
phone: "123456789",
},
{
name: "Henry",
surname: "Williams",
age: 70,
phone: "987654321",
},
{
name: "Ivy",
surname: "Brown",
age: 75,
phone: "123456789",
},
{
name: "Jack",
surname: "Brown",
age: 80,
phone: "987654321",
},
{
name: "Kelly",
surname: "Johnson",
age: 85,
phone: "123456789",
},
{
name: "Liam",
surname: "Johnson",
age: 90,
phone: "987654321",
},
{
name: "Mia",
surname: "Williams",
age: 95,
phone: "123456789",
},
{
name: "Nathan",
surname: "Williams",
age: 100,
phone: "987654321",
},
];
export { columns, data };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/) * Copyright (C) 2019-2024 CZ.NIC z.s.p.o. (https://www.nic.cz/)
* *
* This is free software, licensed under the GNU General Public License v3. * This is free software, licensed under the GNU General Public License v3.
* See /LICENSE for more information. * See /LICENSE for more information.
@ -9,7 +9,7 @@ import React, { useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { QRCodeSVG } from "qrcode.react"; import QRCode from "qrcode.react";
import { createAndDownloadPdf, toQRCodeContent } from "./qrCodeHelpers"; import { createAndDownloadPdf, toQRCodeContent } from "./qrCodeHelpers";
import Button from "../../bootstrap/Button"; import Button from "../../bootstrap/Button";
@ -33,7 +33,10 @@ export default function WiFiQRCode({ SSID, password }) {
<button <button
type="button" type="button"
className="input-group-text" className="input-group-text"
onClick={() => setModal(true)} onClick={(e) => {
e.preventDefault();
setModal(true);
}}
> >
<FontAwesomeIcon <FontAwesomeIcon
icon="fa-solid fa-qrcode" icon="fa-solid fa-qrcode"
@ -42,14 +45,14 @@ export default function WiFiQRCode({ SSID, password }) {
className="text-secondary" className="text-secondary"
/> />
</button> </button>
{modal && ( {modal ? (
<QRCodeModal <QRCodeModal
setShown={setModal} setShown={setModal}
shown={modal} shown={modal}
SSID={SSID} SSID={SSID}
password={password} password={password}
/> />
)} ) : null}
</> </>
); );
} }
@ -66,30 +69,31 @@ function QRCodeModal({ shown, setShown, SSID, password }) {
<Modal setShown={setShown} shown={shown}> <Modal setShown={setShown} shown={shown}>
<ModalHeader setShown={setShown} title={_("Wi-Fi QR Code")} /> <ModalHeader setShown={setShown} title={_("Wi-Fi QR Code")} />
<ModalBody> <ModalBody>
<QRCodeSVG <QRCode
className="d-block mx-auto img-logo-black" className="d-block mx-auto img-logo-black"
renderAs="svg"
value={toQRCodeContent(SSID, password)} value={toQRCodeContent(SSID, password)}
level="M" level="M"
size={350} size={350}
marginSize={0} includeMargin
imageSettings={{
src: "/reforis/static/reforis/imgs/turris.svg",
height: 40,
width: 40,
excavate: true,
}}
/> />
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button
className="btn-secondary" className="btn-secondary"
onClick={() => setShown(false)} onClick={(e) => {
e.preventDefault();
setShown(false);
}}
> >
{_("Close")} {_("Close")}
</Button> </Button>
<Button <Button
className="btn-primary" className="btn-primary"
onClick={() => createAndDownloadPdf(SSID, password)} onClick={(e) => {
e.preventDefault();
createAndDownloadPdf(SSID, password);
}}
> >
<FontAwesomeIcon <FontAwesomeIcon
icon="fa-solid fa-file-download" icon="fa-solid fa-file-download"

View File

@ -13,7 +13,7 @@ exports[`<SubmitButton/> Render load 1`] = `
role="status" role="status"
/> />
<span> <span>
Loading Load settings
</span> </span>
</button> </button>
</div> </div>

View File

@ -6,10 +6,8 @@ comfort API and allows to create typical Foris module forms easily.
You can pass more forms as children. You can pass more forms as children.
```jsx static ```js
export default function WAN({ ws }) { <ForisForm
return (
<ForisForm
ws={ws} ws={ws}
forisConfig={{ forisConfig={{
endpoint: API_URLs.wan, endpoint: API_URLs.wan,
@ -18,18 +16,16 @@ export default function WAN({ ws }) {
prepData={prepData} prepData={prepData}
prepDataToSubmit={prepDataToSubmit} prepDataToSubmit={prepDataToSubmit}
validator={validator} validator={validator}
> >
<WANForm /> <WANForm />
<WAN6Form /> <WAN6Form />
<MACForm /> <MACForm />
</ForisForm> </ForisForm>
);
}
``` ```
### Example of children forms `props` usage ### Example of children forms `props` usage
```jsx static ```js
export default function MACForm({ export default function MACForm({
formData, formData,
formErrors, formErrors,
@ -68,9 +64,9 @@ export default function MACForm({
} }
``` ```
The `<ForisForm/>` passes subsequent `props` to the child components. The <ForisForm/> passes subsequent `props` to the child components.
| Prop name | Type | Description | | Prop | Type | Description |
| -------------- | ------ | -------------------------------------------------------------------------- | | -------------- | ------ | -------------------------------------------------------------------------- |
| `formData` | object | Data returned from API. | | `formData` | object | Data returned from API. |
| `formErrors` | object | Errors returned after validation via validator. | | `formErrors` | object | Errors returned after validation via validator. |

View File

@ -18,11 +18,8 @@ export const STATES = {
}; };
SubmitButton.propTypes = { SubmitButton.propTypes = {
/** Disable button */
disabled: PropTypes.bool, disabled: PropTypes.bool,
/** Button state */
state: PropTypes.oneOf(Object.keys(STATES).map((key) => STATES[key])), state: PropTypes.oneOf(Object.keys(STATES).map((key) => STATES[key])),
/** Button label */
label: PropTypes.string, label: PropTypes.string,
}; };
@ -37,7 +34,7 @@ export function SubmitButton({ disabled, state, label, ...props }) {
labelSubmitButton = _("Updating"); labelSubmitButton = _("Updating");
break; break;
case STATES.LOAD: case STATES.LOAD:
labelSubmitButton = _("Loading"); labelSubmitButton = _("Load settings");
break; break;
default: default:
labelSubmitButton = _("Save"); labelSubmitButton = _("Save");

View File

@ -1,12 +0,0 @@
SubmitButton is a component that renders a button with different states based on
the `state` prop. It can be used to indicate the status of a form submission.
```jsx padded
<SubmitButton state={1} />
<SubmitButton state={2} />
<SubmitButton state={3} />
<SubmitButton label="Submitting" state={2} />
```

View File

@ -1,11 +1,10 @@
/* /*
* Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/) * Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (https://www.nic.cz/)
* *
* This is free software, licensed under the GNU General Public License v3. * This is free software, licensed under the GNU General Public License v3.
* See /LICENSE for more information. * See /LICENSE for more information.
*/ */
const path = require("path"); const path = require("path");
const pjson = require("./package.json"); const pjson = require("./package.json");
module.exports = { module.exports = {
@ -16,50 +15,6 @@ module.exports = {
link: "#0075a3", link: "#0075a3",
linkHover: "#00a2e2", linkHover: "#00a2e2",
}, },
fontFamily: {
base: '"Roboto", sans-serif',
},
sidebarWidth: 255,
},
template: {
favicon: "/docs/components/logo.svg",
head: {
links: [
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css?family=Roboto",
},
],
},
},
styles: {
StyleGuide: {
logo: {
display: "flex",
alignItems: "center",
},
},
Logo: {
logo: {
display: "inline-flex",
},
},
Version: {
version: {
display: "inline-flex",
margin: "none",
marginLeft: "8px",
fontSize: "0.6rem",
fontWeight: "bold",
padding: "0.1rem 0.2rem",
color: "#fff",
backgroundColor: "#6c757d",
borderRadius: "5px",
textAlign: "center",
verticalAlign: "middle",
whiteSpace: "nowrap",
},
},
}, },
tocMode: "collapse", tocMode: "collapse",
pagePerSection: true, pagePerSection: true,
@ -122,6 +77,9 @@ module.exports = {
usageMode: "expand", usageMode: "expand",
}, },
], ],
template: {
favicon: "/docs/components/logo.svg",
},
require: [ require: [
"babel-polyfill", "babel-polyfill",
path.join(__dirname, "src/testUtils/mockGlobals.js"), path.join(__dirname, "src/testUtils/mockGlobals.js"),