1
0
mirror of https://gitlab.nic.cz/turris/reforis/foris-js.git synced 2025-04-29 09:16:38 +02:00

Merge branch 'dev' into 'master'

Dev

See merge request turris/reforis/foris-js!281
This commit is contained in:
Aleksandr Gumroian 2025-04-22 18:44:13 +02:00
commit 56e3e76af9
28 changed files with 345 additions and 13997 deletions

View File

@ -8,6 +8,24 @@ and this project adheres to
## [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
### Added
@ -468,7 +486,8 @@ and this project adheres to
## [0.0.7] - 2019-09-02
[unreleased]:
https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.7.1...dev
https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.7.2...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.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

View File

@ -1,25 +1,27 @@
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 the
[`npm link`](https://docs.npmjs.com/cli/link).
At some point, you'll likely need to modify the library. When that happens, your
best friend will be [`npm link`](https://docs.npmjs.com/cli/link).
Please, notice that it will not work if you link the library just from the root
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.
**Important Note:** Simply linking from the repo root won't work because the
source files are in `./src`. Instead, you'll need to:
Yeah, it's not such a comfortable solution for development. But it can be fixed
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.
1. First package the library using `make pack`
2. Then link it from the `./dist` directory
So step by step:
While this isn't the most developer-friendly workflow, you can improve it by
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
make pack;
cd dist;
npm link;
# Package and link the library
make pack
cd dist
npm link
cd $project_dir/js # Navigate to JS directory of the project where you want to link the library
# Link to your project
cd /path/to/your/project/js # Navigate to your project's JS directory
npm link foris
```
And that's it ;)

View File

@ -1,35 +1,37 @@
Welcome! This is the official documentation for Foris JS.
Welcome to the official Foris JS documentation!
## What Foris JS is
## About Foris JS
Foris JS library is a set of components and utils for reForis application and
plugins.
Foris JS is a library containing reusable components and utilities designed
specifically for the reForis application and its plugins.
Please notice that all of these components or utils are used in reForis and
plugins. If you want to study them by example, I recommend you to full-text
search those repositories.
**Note:** All components and utilities in this library are actively used in
reForis and its plugins. To see practical examples of how they're implemented,
we recommend searching through those repositories.
# Installation
## Getting Started
## Prerequisites
### Prerequisites
Please make sure that [Node.js](https://nodejs.org/en/) is installed on your
system.
Before installing, ensure you have [Node.js](https://nodejs.org/en/) installed
on your system.
The current Long Term Support (LTS) release is an ideal starting point, see
[here](https://github.com/nodejs/Release#release-schedule).
We recommend using the current Long Term Support (LTS) version for optimal
compatibility. Check the
[release schedule](https://github.com/nodejs/Release#release-schedule) for
details.
## Installation
### Installation
To install the latest release:
Install the latest version with:
```plain
```bash
npm install foris
```
To install a specific version:
Or install a specific version by running:
```plain
```bash
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",
"version": "6.7.1",
"version": "6.7.2",
"description": "Foris JS library is a set of components and utils for reForis application and plugins.",
"author": "CZ.NIC, z.s.p.o.",
"repository": {
@ -62,6 +62,9 @@
"style-loader": "^4.0.0",
"webpack": "^5.98.0"
},
"overrides": {
"markdown-to-jsx": "^7.7.4"
},
"scripts": {
"lint": "eslint 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
component.
```js
```jsx
import { useState } from "react";
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.
```js
```jsx
import React, { useState } from "react";
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
locale.
```js
```jsx
ForisTranslations = { locale: "en" };
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
details.
```js
```jsx
<DownloadButton href="example.zip">Download</DownloadButton>
```

View File

@ -4,10 +4,12 @@ checking. It's only meaningful using inside `<form>`.
All additional `props` are passed to the `<input type="email">` HTML component.
```js
```jsx
import { useState } from "react";
import Button from "./Button";
const [email, setEmail] = useState("Wrong email");
<form onSubmit={(e) => e.preventDefault()}>
<EmailInput
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.
```js
```jsx
import { useState } from "react";
const [files, setFiles] = useState([]);
@ -23,7 +23,7 @@ const label = files.length === 1 ? files[0].name : "Choose file";
### FileInput with multiple files
```js
```jsx
import { useState } from "react";
const [files, setFiles] = useState([]);

View File

@ -6,9 +6,9 @@ the page since modals are rendered in portals.
Modals also have three optional sizes, which can be defined through the `size`
prop:
- small - `sm`
- large - `lg`
- extra-large - `xl`
- small - `sm`
- large - `lg`
- extra-large - `xl`
For more details please visit Bootstrap
<a href="https://getbootstrap.com/docs/4.5/components/modal/#optional-sizes" target="_blank">
@ -18,7 +18,7 @@ documentation</a>.
<div id="modal-container" />
```
```js
```jsx
import { ModalHeader, ModalBody, ModalFooter } from "./Modal";
import { useState } from "react";

View File

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

View File

@ -5,8 +5,9 @@ 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.
```js
```jsx
import { useState } from "react";
const CHOICES = [
{ value: "one", label: "1" },
{ value: "two", label: "2" },

View File

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

View File

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

View File

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

View File

@ -3,8 +3,9 @@ using in foris forms.
All additional `props` are passed to the `<input type="text">` HTML component.
```js
```jsx
import { useState } from "react";
const [value, setValue] = useState("Bla bla");
<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
performed on a particular item.
```js
```jsx
import { useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";

View File

@ -4,132 +4,14 @@ Rich Table is a table component based on
[Tanstack React Table](https://tanstack.com/table/). It adds some features to
the table component, such as:
- **Pagination**: The table can be paginated.
- **Sorting**: The table can be sorted by columns.
- **Row Expansion**: The table rows can be expanded. (To be implemented)
- **Pagination**: The table can be paginated.
- **Sorting**: The table can be sorted by columns.
- **Row Expansion**: The table rows can be expanded. (To be implemented)
### Example
```js
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",
},
];
```jsx
import { columns, data } from "./mockData";
<RichTable columns={columns} data={data} withPagination />;
```

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,12 @@
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,10 +1,11 @@
/*
* Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (https://www.nic.cz/)
* Copyright (C) 2019-2025 CZ.NIC z.s.p.o. (https://www.nic.cz/)
*
* This is free software, licensed under the GNU General Public License v3.
* See /LICENSE for more information.
*/
const path = require("path");
const pjson = require("./package.json");
module.exports = {
@ -15,6 +16,50 @@ module.exports = {
link: "#0075a3",
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",
pagePerSection: true,
@ -77,9 +122,6 @@ module.exports = {
usageMode: "expand",
},
],
template: {
favicon: "/docs/components/logo.svg",
},
require: [
"babel-polyfill",
path.join(__dirname, "src/testUtils/mockGlobals.js"),