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

Compare commits

...

9 Commits

Author SHA1 Message Date
cdf39345f1 WiFi API update
Deprecated option `hwmode=11g/11a` was replaced by `band=2g/5g/6g`
2024-10-17 12:11:16 +02:00
14b90bbbd4 Merge branch 'dev' into 'master'
Dev

See merge request turris/reforis/foris-js!251
2024-10-02 14:35:17 +02:00
85b207b1dd Merge branch 'bump-version-640' into 'dev'
Bump v6.4.0

See merge request turris/reforis/foris-js!250
2024-10-02 14:31:57 +02:00
79e61d9507 Bump v6.4.0
* Refactor Alert component to include dismiss animation and timeout
* Refactor ThreeDotsMenu component to include additional props
2024-10-02 14:30:09 +02:00
6795c3941b Merge branch 'add-alert-animation-and-timeout' into 'dev'
Add Alert animation and timeout

See merge request turris/reforis/foris-js!249
2024-10-02 13:48:31 +02:00
969e8e6411 Update Snapshots 2024-10-02 13:16:45 +02:00
0099759279 Fix tests 2024-10-02 13:16:37 +02:00
87c81a2a2d Refactor Alert component to include dismiss animation and timeout 2024-10-02 13:14:48 +02:00
81b71f8153 Refactor ThreeDotsMenu component to include additional props 2024-10-02 13:14:40 +02:00
12 changed files with 79 additions and 51 deletions

View File

@ -8,6 +8,13 @@ and this project adheres to
## [Unreleased] ## [Unreleased]
## [6.4.0] - 2024-10-02
### Changed
- Refactored Alert component to include dismiss animation and timeout
- Refactored ThreeDotsMenu component to include additional props
## [6.3.0] - 2024-09-27 ## [6.3.0] - 2024-09-27
### Added ### Added
@ -398,7 +405,8 @@ 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.3.0...dev https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.4.0...dev
[6.4.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.3.0...v6.4.0
[6.3.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.2.1...v6.3.0 [6.3.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.2.1...v6.3.0
[6.2.1]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.2.0...v6.2.1 [6.2.1]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.2.0...v6.2.1
[6.2.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.1.1...v6.2.0 [6.2.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.1.1...v6.2.0

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "foris", "name": "foris",
"version": "6.3.0", "version": "6.4.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "foris", "name": "foris",
"version": "6.3.0", "version": "6.4.0",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.6.0", "@fortawesome/fontawesome-svg-core": "^6.6.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "foris", "name": "foris",
"version": "6.3.0", "version": "6.4.0",
"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": {

View File

@ -5,7 +5,7 @@
* See /LICENSE for more information. * See /LICENSE for more information.
*/ */
import React, { useRef } from "react"; import React, { useRef, useEffect, useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
@ -40,20 +40,36 @@ Alert.defaultProps = {
function Alert({ type, onDismiss, children }) { function Alert({ type, onDismiss, children }) {
const alertRef = useRef(); const alertRef = useRef();
const [isVisible, setIsVisible] = useState(true);
useFocusTrap(alertRef, !!onDismiss); useFocusTrap(alertRef, !!onDismiss);
useEffect(() => {
if (onDismiss) {
const timeout = setTimeout(() => setIsVisible(false), 7000);
return () => clearTimeout(timeout);
}
}, [onDismiss]);
const handleAnimationEnd = () => {
if (!isVisible && onDismiss) {
onDismiss();
}
};
return ( return (
<div <div
ref={alertRef} ref={alertRef}
className={`alert alert-${type} ${ className={`alert alert-${type} ${isVisible ? "alert-fade-in" : "alert-slide-out-top"} ${
onDismiss ? "alert-dismissible" : "" onDismiss ? "alert-dismissible" : ""
}`.trim()} }`.trim()}
role="alert" role="alert"
onAnimationEnd={handleAnimationEnd}
> >
{onDismiss && ( {onDismiss && (
<button <button
type="button" type="button"
className="btn-close" className="btn-close"
onClick={onDismiss} onClick={() => setIsVisible(false)}
aria-label={_("Close")} aria-label={_("Close")}
/> />
)} )}

View File

@ -18,9 +18,9 @@ ThreeDotsMenu.propTypes = {
children: PropTypes.arrayOf(PropTypes.node).isRequired, children: PropTypes.arrayOf(PropTypes.node).isRequired,
}; };
function ThreeDotsMenu({ children }) { function ThreeDotsMenu({ children, ...props }) {
return ( return (
<div className="dropdown"> <div className="dropdown position-static" {...props}>
<Button <Button
className="btn-sm btn-link text-body" className="btn-sm btn-link text-body"
data-bs-toggle="dropdown" data-bs-toggle="dropdown"

View File

@ -9,7 +9,7 @@ import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { HELP_TEXTS, HTMODES, HWMODES, ENCRYPTIONMODES } from "./constants"; import { HELP_TEXTS, HTMODES, BANDS, ENCRYPTIONMODES } from "./constants";
import WifiGuestForm from "./WiFiGuestForm"; import WifiGuestForm from "./WiFiGuestForm";
import WiFiQRCode from "./WiFiQRCode"; import WiFiQRCode from "./WiFiQRCode";
import PasswordInput from "../../bootstrap/PasswordInput"; import PasswordInput from "../../bootstrap/PasswordInput";
@ -60,7 +60,7 @@ DeviceForm.propTypes = {
SSID: PropTypes.string.isRequired, SSID: PropTypes.string.isRequired,
password: PropTypes.string.isRequired, password: PropTypes.string.isRequired,
hidden: PropTypes.bool.isRequired, hidden: PropTypes.bool.isRequired,
hwmode: PropTypes.string.isRequired, band: PropTypes.string.isRequired,
htmode: PropTypes.string.isRequired, htmode: PropTypes.string.isRequired,
channel: PropTypes.string.isRequired, channel: PropTypes.string.isRequired,
guest_wifi: PropTypes.object.isRequired, guest_wifi: PropTypes.object.isRequired,
@ -155,11 +155,11 @@ function DeviceForm({
/> />
<RadioSet <RadioSet
name={`hwmode-${deviceID}`} name={`band-${deviceID}`}
label="GHz" label="GHz"
choices={getHwmodeChoices(formData)} choices={getBandChoices(formData)}
value={formData.hwmode} value={formData.band}
helpText={HELP_TEXTS.hwmode} helpText={HELP_TEXTS.band}
inline inline
onChange={setFormValue((value) => { onChange={setFormValue((value) => {
// Get the last item in an array of available HT modes // Get the last item in an array of available HT modes
@ -168,7 +168,7 @@ function DeviceForm({
return { return {
devices: { devices: {
[deviceIndex]: { [deviceIndex]: {
hwmode: { $set: value }, band: { $set: value },
channel: { $set: "0" }, channel: { $set: "0" },
htmode: { htmode: {
$set: $set:
@ -263,7 +263,7 @@ function getChannelChoices(device) {
}; };
device.available_bands.forEach((availableBand) => { device.available_bands.forEach((availableBand) => {
if (availableBand.hwmode !== device.hwmode) return; if (availableBand.band !== device.band) return;
availableBand.available_channels.forEach((availableChannel) => { availableBand.available_channels.forEach((availableChannel) => {
channelChoices[availableChannel.number.toString()] = ` channelChoices[availableChannel.number.toString()] = `
@ -282,7 +282,7 @@ function getHtmodeChoices(device) {
const htmodeChoices = {}; const htmodeChoices = {};
device.available_bands.forEach((availableBand) => { device.available_bands.forEach((availableBand) => {
if (availableBand.hwmode !== device.hwmode) return; if (availableBand.band !== device.band) return;
availableBand.available_htmodes.forEach((availableHtmod) => { availableBand.available_htmodes.forEach((availableHtmod) => {
htmodeChoices[availableHtmod] = HTMODES[availableHtmod]; htmodeChoices[availableHtmod] = HTMODES[availableHtmod];
@ -291,10 +291,10 @@ function getHtmodeChoices(device) {
return htmodeChoices; return htmodeChoices;
} }
function getHwmodeChoices(device) { function getBandChoices(device) {
return device.available_bands.map((availableBand) => ({ return device.available_bands.map((availableBand) => ({
label: HWMODES[availableBand.hwmode], label: BANDS[availableBand.band],
value: availableBand.hwmode, value: availableBand.band,
})); }));
} }

View File

@ -118,7 +118,7 @@ describe("<WiFiSettings/>", () => {
guest_wifi: { enabled: false }, guest_wifi: { enabled: false },
hidden: false, hidden: false,
htmode: "HT80", htmode: "HT80",
hwmode: "11a", band: "5g",
id: 0, id: 0,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -148,7 +148,7 @@ describe("<WiFiSettings/>", () => {
guest_wifi: { enabled: false }, guest_wifi: { enabled: false },
hidden: false, hidden: false,
htmode: "VHT80", htmode: "VHT80",
hwmode: "11g", band: "2g",
id: 0, id: 0,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -185,7 +185,7 @@ describe("<WiFiSettings/>", () => {
}, },
hidden: false, hidden: false,
htmode: "HT80", htmode: "HT80",
hwmode: "11a", band: "5g",
id: 0, id: 0,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",

View File

@ -77,7 +77,7 @@ export function wifiSettingsFixture() {
"VHT40", "VHT40",
"VHT80", "VHT80",
], ],
hwmode: "11g", band: "2g",
}, },
{ {
available_channels: [ available_channels: [
@ -215,7 +215,7 @@ export function wifiSettingsFixture() {
"VHT40", "VHT40",
"VHT80", "VHT80",
], ],
hwmode: "11a", band: "5g",
}, },
], ],
channel: 60, channel: 60,
@ -227,7 +227,7 @@ export function wifiSettingsFixture() {
}, },
hidden: false, hidden: false,
htmode: "HT80", htmode: "HT80",
hwmode: "11a", band: "5g",
id: 0, id: 0,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -294,7 +294,7 @@ export function wifiSettingsFixture() {
}, },
], ],
available_htmodes: ["NOHT", "HT20", "HT40"], available_htmodes: ["NOHT", "HT20", "HT40"],
hwmode: "11g", band: "2g",
}, },
], ],
channel: 11, channel: 11,
@ -306,7 +306,7 @@ export function wifiSettingsFixture() {
}, },
hidden: false, hidden: false,
htmode: "HT40", htmode: "HT40",
hwmode: "11g", band: "2g",
id: 1, id: 1,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -323,7 +323,7 @@ const oneDevice = {
guest_wifi: { enabled: false }, guest_wifi: { enabled: false },
hidden: false, hidden: false,
htmode: "HT40", htmode: "HT40",
hwmode: "11a", band: "5g",
id: 0, id: 0,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -340,7 +340,7 @@ const twoDevices = {
guest_wifi: { enabled: false }, guest_wifi: { enabled: false },
hidden: false, hidden: false,
htmode: "HT40", htmode: "HT40",
hwmode: "11a", band: "5g",
id: 0, id: 0,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -352,7 +352,7 @@ const twoDevices = {
guest_wifi: { enabled: false }, guest_wifi: { enabled: false },
hidden: false, hidden: false,
htmode: "HT40", htmode: "HT40",
hwmode: "11a", band: "5g",
id: 1, id: 1,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -369,7 +369,7 @@ const threeDevices = {
guest_wifi: { enabled: false }, guest_wifi: { enabled: false },
hidden: false, hidden: false,
htmode: "HT40", htmode: "HT40",
hwmode: "11a", band: "5g",
id: 0, id: 0,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -381,7 +381,7 @@ const threeDevices = {
guest_wifi: { enabled: false }, guest_wifi: { enabled: false },
hidden: false, hidden: false,
htmode: "HT40", htmode: "HT40",
hwmode: "11a", band: "5g",
id: 1, id: 1,
password: "TestPass", password: "TestPass",
encryption: "WPA3", encryption: "WPA3",
@ -393,7 +393,7 @@ const threeDevices = {
guest_wifi: { enabled: false }, guest_wifi: { enabled: false },
hidden: false, hidden: false,
htmode: "HT40", htmode: "HT40",
hwmode: "11a", band: "5g",
id: 2, id: 2,
password: "", password: "",
encryption: "WPA3", encryption: "WPA3",

View File

@ -562,14 +562,14 @@ exports[`<WiFiSettings/> Snapshot one module enabled. 1`] = `
+ > + >
+ <input + <input
+ class="form-check-input me-2" + class="form-check-input me-2"
+ id="hwmode-0-0" + id="band-0-0"
+ name="hwmode-0" + name="band-0"
+ type="radio" + type="radio"
+ value="11g" + value="2g"
+ /> + />
+ <label + <label
+ class="form-check-label" + class="form-check-label"
+ for="hwmode-0-0" + for="band-0-0"
+ > + >
+ 2.4 + 2.4
+ </label> + </label>
@ -580,14 +580,14 @@ exports[`<WiFiSettings/> Snapshot one module enabled. 1`] = `
+ <input + <input
+ checked="" + checked=""
+ class="form-check-input me-2" + class="form-check-input me-2"
+ id="hwmode-0-1" + id="band-0-1"
+ name="hwmode-0" + name="band-0"
+ type="radio" + type="radio"
+ value="11a" + value="5g"
+ /> + />
+ <label + <label
+ class="form-check-label" + class="form-check-label"
+ for="hwmode-0-1" + for="band-0-1"
+ > + >
+ 5 + 5
+ </label> + </label>

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2019-2022 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.
@ -18,9 +18,10 @@ export const HTMODES = {
HE80: _("802.11ax - 80 MHz wide channel"), HE80: _("802.11ax - 80 MHz wide channel"),
HE160: _("802.11ax - 160 MHz wide channel"), HE160: _("802.11ax - 160 MHz wide channel"),
}; };
export const HWMODES = { export const BANDS = {
"11g": "2.4", "2g": "2.4",
"11a": "5", "5g": "5",
"6g": "6",
}; };
export const ENCRYPTIONMODES = { export const ENCRYPTIONMODES = {
WPA3: _("WPA3 only"), WPA3: _("WPA3 only"),
@ -37,7 +38,7 @@ export const HELP_TEXTS = {
hidden: _( hidden: _(
"If set, network is not visible when scanning for available networks." "If set, network is not visible when scanning for available networks."
), ),
hwmode: _( band: _(
"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 does not carry so well indoors." "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 does not carry so well indoors."
), ),
htmode: _( htmode: _(

View File

@ -43,14 +43,17 @@ describe("AlertContext", () => {
expect(componentContainer).toMatchSnapshot(); expect(componentContainer).toMatchSnapshot();
}); });
it("should dismiss alert with alert button", () => { it("should dismiss alert with alert button", async () => {
fireEvent.click(getByText(componentContainer, "Set alert")); fireEvent.click(getByText(componentContainer, "Set alert"));
// Alert is present // Alert is present
expect(getByText(componentContainer, "Alert content")).toBeDefined(); expect(getByText(componentContainer, "Alert content")).toBeDefined();
fireEvent.click(componentContainer.querySelector(".btn-close")); fireEvent.click(componentContainer.querySelector(".btn-close"));
// Alert is gone // Alert is gone
expect(queryByText(componentContainer, "Alert content")).toBeNull(); await (() =>
expect(
queryByText(componentContainer, "Alert content")
).toBeNull());
}); });
it("should dismiss alert with external button", () => { it("should dismiss alert with external button", () => {

View File

@ -6,7 +6,7 @@ exports[`AlertContext should render alert 1`] = `
id="alert-container" id="alert-container"
> >
<div <div
class="alert alert-danger alert-dismissible" class="alert alert-danger alert-fade-in alert-dismissible"
role="alert" role="alert"
> >
<button <button