mirror of
				https://gitlab.nic.cz/turris/reforis/foris-js.git
				synced 2025-11-03 23:00:31 +01:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			v6.2.0
			...
			feature/ws
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					cc1389536e | ||
| 
						 | 
					499be46588 | 
							
								
								
									
										16
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -8,19 +8,6 @@ and this project adheres to
 | 
			
		||||
 | 
			
		||||
## [Unreleased]
 | 
			
		||||
 | 
			
		||||
## [6.2.0] - 2024-09-20
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
 | 
			
		||||
-   Added useFocusTrap hook
 | 
			
		||||
-   Added extendSession endpoint
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
 | 
			
		||||
-   Refactored Spinner.css to use CSS variable for color
 | 
			
		||||
-   Refactored Modal component to use useFocusTrap hook
 | 
			
		||||
-   Refactored Alert component to use useFocusTrap hook
 | 
			
		||||
 | 
			
		||||
## [6.1.1] - 2024-08-30
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
@@ -374,8 +361,7 @@ and this project adheres to
 | 
			
		||||
## [0.0.7] - 2019-09-02
 | 
			
		||||
 | 
			
		||||
[unreleased]:
 | 
			
		||||
    https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.2.0...dev
 | 
			
		||||
[6.2.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.1.1...v6.2.0
 | 
			
		||||
    https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.1.1...master
 | 
			
		||||
[6.1.1]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.1.0...v6.1.1
 | 
			
		||||
[6.1.0]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.0.3...v6.1.0
 | 
			
		||||
[6.0.3]: https://gitlab.nic.cz/turris/reforis/foris-js/-/compare/v6.0.2...v6.0.3
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										128
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										128
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,12 +1,12 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "foris",
 | 
			
		||||
    "version": "6.2.0",
 | 
			
		||||
    "version": "6.1.1",
 | 
			
		||||
    "lockfileVersion": 2,
 | 
			
		||||
    "requires": true,
 | 
			
		||||
    "packages": {
 | 
			
		||||
        "": {
 | 
			
		||||
            "name": "foris",
 | 
			
		||||
            "version": "6.2.0",
 | 
			
		||||
            "version": "6.1.1",
 | 
			
		||||
            "license": "GPL-3.0",
 | 
			
		||||
            "dependencies": {
 | 
			
		||||
                "@fortawesome/fontawesome-svg-core": "^6.6.0",
 | 
			
		||||
@@ -18,7 +18,8 @@
 | 
			
		||||
                "moment": "^2.30.1",
 | 
			
		||||
                "qrcode.react": "^3.1.0",
 | 
			
		||||
                "react-datetime": "^3.2.0",
 | 
			
		||||
                "react-uid": "^2.3.3"
 | 
			
		||||
                "react-uid": "^2.3.3",
 | 
			
		||||
                "socket.io-client": "^4.6.1"
 | 
			
		||||
            },
 | 
			
		||||
            "devDependencies": {
 | 
			
		||||
                "@babel/cli": "^7.24.7",
 | 
			
		||||
@@ -3583,6 +3584,12 @@
 | 
			
		||||
                "@sinonjs/commons": "^3.0.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/@socket.io/component-emitter": {
 | 
			
		||||
            "version": "3.1.2",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
 | 
			
		||||
            "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
 | 
			
		||||
            "license": "MIT"
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/@testing-library/dom": {
 | 
			
		||||
            "version": "5.6.1",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-5.6.1.tgz",
 | 
			
		||||
@@ -6372,7 +6379,6 @@
 | 
			
		||||
            "version": "4.3.5",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
 | 
			
		||||
            "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
 | 
			
		||||
            "dev": true,
 | 
			
		||||
            "dependencies": {
 | 
			
		||||
                "ms": "2.1.2"
 | 
			
		||||
            },
 | 
			
		||||
@@ -6722,6 +6728,28 @@
 | 
			
		||||
                "node": ">= 0.8"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/engine.io-client": {
 | 
			
		||||
            "version": "6.5.4",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
 | 
			
		||||
            "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
 | 
			
		||||
            "license": "MIT",
 | 
			
		||||
            "dependencies": {
 | 
			
		||||
                "@socket.io/component-emitter": "~3.1.0",
 | 
			
		||||
                "debug": "~4.3.1",
 | 
			
		||||
                "engine.io-parser": "~5.2.1",
 | 
			
		||||
                "ws": "~8.17.1",
 | 
			
		||||
                "xmlhttprequest-ssl": "~2.0.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/engine.io-parser": {
 | 
			
		||||
            "version": "5.2.3",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
 | 
			
		||||
            "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
 | 
			
		||||
            "license": "MIT",
 | 
			
		||||
            "engines": {
 | 
			
		||||
                "node": ">=10.0.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/enhanced-resolve": {
 | 
			
		||||
            "version": "5.17.1",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
 | 
			
		||||
@@ -13948,8 +13976,7 @@
 | 
			
		||||
        "node_modules/ms": {
 | 
			
		||||
            "version": "2.1.2",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
 | 
			
		||||
            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
 | 
			
		||||
            "dev": true
 | 
			
		||||
            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/multicast-dns": {
 | 
			
		||||
            "version": "7.2.5",
 | 
			
		||||
@@ -16552,6 +16579,34 @@
 | 
			
		||||
            "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
 | 
			
		||||
            "dev": true
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/socket.io-client": {
 | 
			
		||||
            "version": "4.7.5",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
 | 
			
		||||
            "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
 | 
			
		||||
            "license": "MIT",
 | 
			
		||||
            "dependencies": {
 | 
			
		||||
                "@socket.io/component-emitter": "~3.1.0",
 | 
			
		||||
                "debug": "~4.3.2",
 | 
			
		||||
                "engine.io-client": "~6.5.2",
 | 
			
		||||
                "socket.io-parser": "~4.2.4"
 | 
			
		||||
            },
 | 
			
		||||
            "engines": {
 | 
			
		||||
                "node": ">=10.0.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/socket.io-parser": {
 | 
			
		||||
            "version": "4.2.4",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
 | 
			
		||||
            "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
 | 
			
		||||
            "license": "MIT",
 | 
			
		||||
            "dependencies": {
 | 
			
		||||
                "@socket.io/component-emitter": "~3.1.0",
 | 
			
		||||
                "debug": "~4.3.1"
 | 
			
		||||
            },
 | 
			
		||||
            "engines": {
 | 
			
		||||
                "node": ">=10.0.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/sockjs": {
 | 
			
		||||
            "version": "0.3.24",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
 | 
			
		||||
@@ -18360,7 +18415,6 @@
 | 
			
		||||
            "version": "8.17.1",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
 | 
			
		||||
            "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
 | 
			
		||||
            "dev": true,
 | 
			
		||||
            "license": "MIT",
 | 
			
		||||
            "engines": {
 | 
			
		||||
                "node": ">=10.0.0"
 | 
			
		||||
@@ -18393,6 +18447,14 @@
 | 
			
		||||
            "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
 | 
			
		||||
            "dev": true
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/xmlhttprequest-ssl": {
 | 
			
		||||
            "version": "2.0.0",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
 | 
			
		||||
            "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
 | 
			
		||||
            "engines": {
 | 
			
		||||
                "node": ">=0.4.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "node_modules/yallist": {
 | 
			
		||||
            "version": "4.0.0",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 | 
			
		||||
@@ -21053,6 +21115,11 @@
 | 
			
		||||
                "@sinonjs/commons": "^3.0.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "@socket.io/component-emitter": {
 | 
			
		||||
            "version": "3.1.2",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
 | 
			
		||||
            "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
 | 
			
		||||
        },
 | 
			
		||||
        "@testing-library/dom": {
 | 
			
		||||
            "version": "5.6.1",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-5.6.1.tgz",
 | 
			
		||||
@@ -23262,7 +23329,6 @@
 | 
			
		||||
            "version": "4.3.5",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
 | 
			
		||||
            "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
 | 
			
		||||
            "dev": true,
 | 
			
		||||
            "requires": {
 | 
			
		||||
                "ms": "2.1.2"
 | 
			
		||||
            }
 | 
			
		||||
@@ -23522,6 +23588,23 @@
 | 
			
		||||
            "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
 | 
			
		||||
            "dev": true
 | 
			
		||||
        },
 | 
			
		||||
        "engine.io-client": {
 | 
			
		||||
            "version": "6.5.4",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
 | 
			
		||||
            "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
 | 
			
		||||
            "requires": {
 | 
			
		||||
                "@socket.io/component-emitter": "~3.1.0",
 | 
			
		||||
                "debug": "~4.3.1",
 | 
			
		||||
                "engine.io-parser": "~5.2.1",
 | 
			
		||||
                "ws": "~8.17.1",
 | 
			
		||||
                "xmlhttprequest-ssl": "~2.0.0"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "engine.io-parser": {
 | 
			
		||||
            "version": "5.2.3",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
 | 
			
		||||
            "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="
 | 
			
		||||
        },
 | 
			
		||||
        "enhanced-resolve": {
 | 
			
		||||
            "version": "5.17.1",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
 | 
			
		||||
@@ -28947,8 +29030,7 @@
 | 
			
		||||
        "ms": {
 | 
			
		||||
            "version": "2.1.2",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
 | 
			
		||||
            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
 | 
			
		||||
            "dev": true
 | 
			
		||||
            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
 | 
			
		||||
        },
 | 
			
		||||
        "multicast-dns": {
 | 
			
		||||
            "version": "7.2.5",
 | 
			
		||||
@@ -30877,6 +30959,26 @@
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "socket.io-client": {
 | 
			
		||||
            "version": "4.7.5",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
 | 
			
		||||
            "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
 | 
			
		||||
            "requires": {
 | 
			
		||||
                "@socket.io/component-emitter": "~3.1.0",
 | 
			
		||||
                "debug": "~4.3.2",
 | 
			
		||||
                "engine.io-client": "~6.5.2",
 | 
			
		||||
                "socket.io-parser": "~4.2.4"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "socket.io-parser": {
 | 
			
		||||
            "version": "4.2.4",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
 | 
			
		||||
            "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
 | 
			
		||||
            "requires": {
 | 
			
		||||
                "@socket.io/component-emitter": "~3.1.0",
 | 
			
		||||
                "debug": "~4.3.1"
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "sockjs": {
 | 
			
		||||
            "version": "0.3.24",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
 | 
			
		||||
@@ -32198,7 +32300,6 @@
 | 
			
		||||
            "version": "8.17.1",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
 | 
			
		||||
            "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
 | 
			
		||||
            "dev": true,
 | 
			
		||||
            "requires": {}
 | 
			
		||||
        },
 | 
			
		||||
        "xml-name-validator": {
 | 
			
		||||
@@ -32213,6 +32314,11 @@
 | 
			
		||||
            "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
 | 
			
		||||
            "dev": true
 | 
			
		||||
        },
 | 
			
		||||
        "xmlhttprequest-ssl": {
 | 
			
		||||
            "version": "2.0.0",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
 | 
			
		||||
            "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
 | 
			
		||||
        },
 | 
			
		||||
        "yallist": {
 | 
			
		||||
            "version": "4.0.0",
 | 
			
		||||
            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "foris",
 | 
			
		||||
    "version": "6.2.0",
 | 
			
		||||
    "version": "6.1.1",
 | 
			
		||||
    "description": "Foris JS library is a set of components and utils for reForis application and plugins.",
 | 
			
		||||
    "author": "CZ.NIC, z.s.p.o.",
 | 
			
		||||
    "repository": {
 | 
			
		||||
@@ -23,7 +23,8 @@
 | 
			
		||||
        "moment": "^2.30.1",
 | 
			
		||||
        "qrcode.react": "^3.1.0",
 | 
			
		||||
        "react-datetime": "^3.2.0",
 | 
			
		||||
        "react-uid": "^2.3.3"
 | 
			
		||||
        "react-uid": "^2.3.3",
 | 
			
		||||
        "socket.io-client": "^4.6.1"
 | 
			
		||||
    },
 | 
			
		||||
    "peerDependencies": {
 | 
			
		||||
        "bootstrap": "^5.3.3",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,10 @@
 | 
			
		||||
 * See /LICENSE for more information.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import React, { useRef } from "react";
 | 
			
		||||
import React from "react";
 | 
			
		||||
 | 
			
		||||
import PropTypes from "prop-types";
 | 
			
		||||
 | 
			
		||||
import { useFocusTrap } from "../utils/hooks";
 | 
			
		||||
 | 
			
		||||
export const ALERT_TYPES = Object.freeze({
 | 
			
		||||
    PRIMARY: "primary",
 | 
			
		||||
    SECONDARY: "secondary",
 | 
			
		||||
@@ -39,15 +37,11 @@ Alert.defaultProps = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function Alert({ type, onDismiss, children }) {
 | 
			
		||||
    const alertRef = useRef();
 | 
			
		||||
    useFocusTrap(alertRef, !!onDismiss);
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            ref={alertRef}
 | 
			
		||||
            className={`alert alert-${type} ${
 | 
			
		||||
                onDismiss ? "alert-dismissible" : ""
 | 
			
		||||
            }`.trim()}
 | 
			
		||||
            role="alert"
 | 
			
		||||
        >
 | 
			
		||||
            {onDismiss && (
 | 
			
		||||
                <button
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ import React, { useRef, useEffect } from "react";
 | 
			
		||||
 | 
			
		||||
import PropTypes from "prop-types";
 | 
			
		||||
 | 
			
		||||
import { useClickOutside, useFocusTrap } from "../utils/hooks";
 | 
			
		||||
import { useClickOutside } from "../utils/hooks";
 | 
			
		||||
import Portal from "../utils/Portal";
 | 
			
		||||
import "./Modal.css";
 | 
			
		||||
 | 
			
		||||
@@ -29,11 +29,10 @@ Modal.propTypes = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function Modal({ shown, setShown, scrollable, size, children }) {
 | 
			
		||||
    const modalRef = useRef();
 | 
			
		||||
    const dialogRef = useRef();
 | 
			
		||||
    let modalSize = "modal-";
 | 
			
		||||
 | 
			
		||||
    useClickOutside(modalRef, () => setShown(false));
 | 
			
		||||
    useFocusTrap(modalRef, shown);
 | 
			
		||||
    useClickOutside(dialogRef, () => setShown(false));
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        const handleEsc = (event) => {
 | 
			
		||||
@@ -66,13 +65,11 @@ export function Modal({ shown, setShown, scrollable, size, children }) {
 | 
			
		||||
    return (
 | 
			
		||||
        <Portal containerId="modal-container">
 | 
			
		||||
            <div
 | 
			
		||||
                ref={modalRef}
 | 
			
		||||
                className={`modal fade ${shown ? "show" : ""}`.trim()}
 | 
			
		||||
                role="dialog"
 | 
			
		||||
                aria-modal="true"
 | 
			
		||||
                aria-labelledby="modal-title"
 | 
			
		||||
            >
 | 
			
		||||
                <div
 | 
			
		||||
                    ref={dialogRef}
 | 
			
		||||
                    className={`${modalSize.trim()} modal-dialog modal-dialog-centered ${
 | 
			
		||||
                        scrollable ? "modal-dialog-scrollable" : ""
 | 
			
		||||
                    }`.trim()}
 | 
			
		||||
@@ -93,7 +90,7 @@ ModalHeader.propTypes = {
 | 
			
		||||
export function ModalHeader({ setShown, title }) {
 | 
			
		||||
    return (
 | 
			
		||||
        <div className="modal-header">
 | 
			
		||||
            <h1 className="modal-title fs-5">{title}</h1>
 | 
			
		||||
            <h5 className="modal-title">{title}</h5>
 | 
			
		||||
            <button
 | 
			
		||||
                type="button"
 | 
			
		||||
                className="btn-close"
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
.spinner-wrapper .spinner-border {
 | 
			
		||||
    width: 4rem;
 | 
			
		||||
    height: 4rem;
 | 
			
		||||
    color: var(--bs-primary);
 | 
			
		||||
    color: #00a2e2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.spinner-fs-background {
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ function ResetWiFiSettings({ ws, endpoint }) {
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        const module = "wifi";
 | 
			
		||||
        ws.subscribe(module).bind(module, "reset", () => {
 | 
			
		||||
        ws.bind(module, "reset", () => {
 | 
			
		||||
            // eslint-disable-next-line no-restricted-globals
 | 
			
		||||
            setTimeout(() => location.reload(), 1000);
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ describe("<RebootButton/>", () => {
 | 
			
		||||
        fireEvent.click(getByText(componentContainer, "Reboot"));
 | 
			
		||||
        fireEvent.click(getByText(componentContainer, "Confirm reboot"));
 | 
			
		||||
        expect(mockAxios.post).toHaveBeenCalledWith(
 | 
			
		||||
            "/reforis/api/reboot",
 | 
			
		||||
            "/api/reboot",
 | 
			
		||||
            undefined,
 | 
			
		||||
            expect.anything()
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,6 @@ exports[`<RebootButton/> Render modal. 1`] = `
 | 
			
		||||
    id="modal-container"
 | 
			
		||||
  >
 | 
			
		||||
    <div
 | 
			
		||||
      aria-labelledby="modal-title"
 | 
			
		||||
      aria-modal="true"
 | 
			
		||||
      class="modal fade show"
 | 
			
		||||
      role="dialog"
 | 
			
		||||
    >
 | 
			
		||||
@@ -21,11 +19,11 @@ exports[`<RebootButton/> Render modal. 1`] = `
 | 
			
		||||
          <div
 | 
			
		||||
            class="modal-header"
 | 
			
		||||
          >
 | 
			
		||||
            <h1
 | 
			
		||||
              class="modal-title fs-5"
 | 
			
		||||
            <h5
 | 
			
		||||
              class="modal-title"
 | 
			
		||||
            >
 | 
			
		||||
              Warning!
 | 
			
		||||
            </h1>
 | 
			
		||||
            </h5>
 | 
			
		||||
            <button
 | 
			
		||||
              aria-label="Close"
 | 
			
		||||
              class="btn-close"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ exports[`AlertContext should render alert 1`] = `
 | 
			
		||||
  >
 | 
			
		||||
    <div
 | 
			
		||||
      class="alert alert-danger alert-dismissible"
 | 
			
		||||
      role="alert"
 | 
			
		||||
    >
 | 
			
		||||
      <button
 | 
			
		||||
        aria-label="Close"
 | 
			
		||||
 
 | 
			
		||||
@@ -10,3 +10,4 @@ global._ = (str) => str;
 | 
			
		||||
global.ngettext = (str) => str;
 | 
			
		||||
global.babel = { format: (str) => str };
 | 
			
		||||
global.ForisTranslations = { locale: "en" };
 | 
			
		||||
global.setImmediate = (fn) => setTimeout(fn, 0);
 | 
			
		||||
@@ -5,14 +5,12 @@
 | 
			
		||||
 * See /LICENSE for more information.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export const REFORIS_URL_PREFIX = "/reforis";
 | 
			
		||||
export const REFORIS_URL_PREFIX = process.env.REFORIS_PREFIX || "";
 | 
			
		||||
export const REFORIS_API_URL_PREFIX = `${REFORIS_URL_PREFIX}/api`;
 | 
			
		||||
 | 
			
		||||
export const ForisURLs = {
 | 
			
		||||
    // turris-auth
 | 
			
		||||
    login: `/login?${REFORIS_URL_PREFIX}/`,
 | 
			
		||||
    logout: `/logout`,
 | 
			
		||||
    extendSession: `/extend-session`,
 | 
			
		||||
 | 
			
		||||
    static: `${REFORIS_URL_PREFIX}/static/reforis`,
 | 
			
		||||
    wifi: `${REFORIS_URL_PREFIX}/network-settings/wifi`,
 | 
			
		||||
 
 | 
			
		||||
@@ -40,40 +40,3 @@ export function useClickOutside(element, callback) {
 | 
			
		||||
        };
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Trap focus inside element. */
 | 
			
		||||
export function useFocusTrap(elementRef, condition = true) {
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (!condition) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        const currentElement = elementRef.current;
 | 
			
		||||
        const focusableElements = currentElement.querySelectorAll(
 | 
			
		||||
            'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
 | 
			
		||||
        );
 | 
			
		||||
        const firstElement = focusableElements[0];
 | 
			
		||||
        const lastElement = focusableElements[focusableElements.length - 1];
 | 
			
		||||
 | 
			
		||||
        const handleTab = (event) => {
 | 
			
		||||
            if (event.key === "Tab") {
 | 
			
		||||
                if (event.shiftKey) {
 | 
			
		||||
                    if (document.activeElement === firstElement) {
 | 
			
		||||
                        lastElement.focus();
 | 
			
		||||
                        event.preventDefault();
 | 
			
		||||
                    }
 | 
			
		||||
                } else if (document.activeElement === lastElement) {
 | 
			
		||||
                    firstElement.focus();
 | 
			
		||||
                    event.preventDefault();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        currentElement.addEventListener("keydown", handleTab);
 | 
			
		||||
 | 
			
		||||
        firstElement.focus();
 | 
			
		||||
 | 
			
		||||
        return () => {
 | 
			
		||||
            currentElement.removeEventListener("keydown", handleTab);
 | 
			
		||||
        };
 | 
			
		||||
    }, [elementRef, condition]);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2020-2022 CZ.NIC z.s.p.o. (http://www.nic.cz/)
 | 
			
		||||
 * Copyright (C) 2020-2024 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.
 | 
			
		||||
@@ -7,47 +7,33 @@
 | 
			
		||||
 | 
			
		||||
/* eslint no-console: "off" */
 | 
			
		||||
 | 
			
		||||
const PROTOCOL = window.location.protocol === "http:" ? "ws" : "wss";
 | 
			
		||||
import { io } from "socket.io-client";
 | 
			
		||||
 | 
			
		||||
const URL = process.env.LIGHTTPD
 | 
			
		||||
    ? `${PROTOCOL}://${window.location.host}/${process.env.WSPATH || "foris-ws"}`
 | 
			
		||||
    : `${PROTOCOL}://${window.location.hostname}:9081`;
 | 
			
		||||
 | 
			
		||||
const WAITING_FOR_CONNECTION_TIMEOUT = 500;
 | 
			
		||||
import { REFORIS_URL_PREFIX } from "../utils/forisUrls";
 | 
			
		||||
 | 
			
		||||
class WebSockets {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.ws = new WebSocket(URL);
 | 
			
		||||
        this.ws.onerror = (e) => {
 | 
			
		||||
            console.error("WS: Error:", e);
 | 
			
		||||
        };
 | 
			
		||||
        this.ws.onmessage = (e) => {
 | 
			
		||||
            console.debug(`WS: Received Message: ${e.data}`);
 | 
			
		||||
            const data = JSON.parse(e.data);
 | 
			
		||||
            this.dispatch(data);
 | 
			
		||||
        };
 | 
			
		||||
        this.ws.onopen = () => {
 | 
			
		||||
            console.debug("WS: Connection open.");
 | 
			
		||||
        };
 | 
			
		||||
        this.ws.onclose = () => {
 | 
			
		||||
            console.debug("WS: Connection closed.");
 | 
			
		||||
        };
 | 
			
		||||
        this.socket = io("/notifications", {
 | 
			
		||||
            path: `${REFORIS_URL_PREFIX}/reforis-ws`,
 | 
			
		||||
        });
 | 
			
		||||
        this.connection = null;
 | 
			
		||||
        this.socket.on("disconnect", (reason) => {
 | 
			
		||||
            this.connection = null;
 | 
			
		||||
            console.debug(`SocketIO disconnected (${reason})`);
 | 
			
		||||
        });
 | 
			
		||||
        this.socket.on("notification", (message) => {
 | 
			
		||||
            console.debug("WS: Received Message:", message);
 | 
			
		||||
            this.dispatch(message);
 | 
			
		||||
        });
 | 
			
		||||
        this.socket.on("connect", (connection) => {
 | 
			
		||||
            this.connection = connection;
 | 
			
		||||
            console.debug(`SocketIO connected.`);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // callbacks[module][action]
 | 
			
		||||
        this.callbacks = {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    waitForConnection(callback) {
 | 
			
		||||
        if (this.ws.readyState === 1) {
 | 
			
		||||
            callback();
 | 
			
		||||
        } else {
 | 
			
		||||
            const that = this;
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
                that.waitForConnection(callback);
 | 
			
		||||
            }, WAITING_FOR_CONNECTION_TIMEOUT);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bind(module, action, callback) {
 | 
			
		||||
        this.callbacks[module] = this.callbacks[module] || {};
 | 
			
		||||
        this.callbacks[module][action] = this.callbacks[module][action] || [];
 | 
			
		||||
@@ -55,13 +41,6 @@ class WebSockets {
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    subscribe(module) {
 | 
			
		||||
        this.waitForConnection(() => {
 | 
			
		||||
            this.send("subscribe", module);
 | 
			
		||||
        });
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unbind(module, action, callback) {
 | 
			
		||||
        const callbacks = this.callbacks[module][action];
 | 
			
		||||
 | 
			
		||||
@@ -75,28 +54,12 @@ class WebSockets {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Object.keys(this.callbacks[module]).length === 0) {
 | 
			
		||||
            this.unsubscribe(module);
 | 
			
		||||
            delete this.callbacks[module];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsubscribe(module) {
 | 
			
		||||
        this.waitForConnection(() => {
 | 
			
		||||
            this.send("unsubscribe", module);
 | 
			
		||||
            delete this.callbacks[module];
 | 
			
		||||
        });
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    send(action, params) {
 | 
			
		||||
        const payload = JSON.stringify({ action, params });
 | 
			
		||||
        this.waitForConnection(() => {
 | 
			
		||||
            this.ws.send(payload);
 | 
			
		||||
        });
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dispatch(json) {
 | 
			
		||||
        if (!json.module) return;
 | 
			
		||||
 | 
			
		||||
@@ -105,20 +68,17 @@ 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.debug(
 | 
			
		||||
                    `Callbacks for this module wasn't found: ${json.module}`
 | 
			
		||||
                );
 | 
			
		||||
            } else throw error;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (typeof chain === "undefined") return;
 | 
			
		||||
 | 
			
		||||
        console.debug("Handling WS message", json);
 | 
			
		||||
        chain.forEach((callback) => callback(json));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    close() {
 | 
			
		||||
        this.ws.close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default WebSockets;
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ function useWSForisModule(
 | 
			
		||||
            setData(message.data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ws.subscribe(module).bind(module, action, callback);
 | 
			
		||||
        ws.bind(module, action, callback);
 | 
			
		||||
 | 
			
		||||
        return () => {
 | 
			
		||||
            ws.unbind(module, action, callback);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user