diff --git a/package-lock.json b/package-lock.json index d690b0a8d2..96e2ab9a32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@alkemio/client-web", - "version": "0.53.5", + "version": "0.53.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@alkemio/client-web", - "version": "0.53.5", + "version": "0.53.6", "license": "EUPL-1.2", "dependencies": { "@alkemio/excalidraw": "^0.17.0-alkemio-2", @@ -17,7 +17,7 @@ "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", "@mui/base": "^5.0.0-beta.23", - "@mui/icons-material": "^5.11.16", + "@mui/icons-material": "^5.15.10", "@mui/lab": "^5.0.0-alpha.56", "@mui/material": "5.13.x", "@mui/styles": "^5.2.0", @@ -2376,9 +2376,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -5162,18 +5162,18 @@ } }, "node_modules/@mui/icons-material": { - "version": "5.11.16", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.16.tgz", - "integrity": "sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==", + "version": "5.15.10", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.10.tgz", + "integrity": "sha512-9cF8oUHZKo9oQ7EQ3pxPELaZuZVmphskU4OI6NiJNDVN7zcuvrEsuWjYo1Zh4fLiC39Nrvm30h/B51rcUjvSGA==", "dependencies": { - "@babel/runtime": "^7.21.0" + "@babel/runtime": "^7.23.9" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@mui/material": "^5.0.0", @@ -6284,18 +6284,6 @@ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, "node_modules/@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", @@ -6527,18 +6515,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@testing-library/dom": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.14.0.tgz", @@ -7273,18 +7249,6 @@ "@types/node": "*" } }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, "node_modules/@types/chai": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", @@ -7919,15 +7883,6 @@ "@types/node": "*" } }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/lodash": { "version": "4.14.182", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", @@ -8111,15 +8066,6 @@ "@types/node": "*" } }, - "node_modules/@types/responselike": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", - "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", @@ -9152,6 +9098,57 @@ "node": "^16.13 || >=18" } }, + "node_modules/@wdio/utils/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@wdio/utils/node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@wdio/utils/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@wdio/utils/node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/@wdio/utils/node_modules/decamelize": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", @@ -9164,6 +9161,125 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wdio/utils/node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/@wdio/utils/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/utils/node_modules/got": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", + "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/@wdio/utils/node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/@wdio/utils/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/utils/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/utils/node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@wdio/utils/node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/@wdio/utils/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -10850,33 +10966,6 @@ "node": ">=8" } }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -11349,18 +11438,6 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -16471,31 +16548,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -17318,19 +17370,6 @@ "npm": ">=1.3.7" } }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -20772,15 +20811,6 @@ "tslib": "^2.0.3" } }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", @@ -21789,15 +21819,6 @@ "node": ">=6" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -22597,15 +22618,6 @@ "node": ">=0.10.0" } }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -27487,18 +27499,6 @@ "node": ">=10" } }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/resq": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/resq/-/resq-1.11.0.tgz", @@ -29283,6 +29283,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/svgo/node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dependencies": { + "boolbase": "~1.0.0" + } + }, "node_modules/swap-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-2.0.2.tgz", @@ -31476,12 +31484,182 @@ "node": "^16.13 || >=18" } }, + "node_modules/webdriver/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/webdriver/node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/webdriver/node_modules/@types/node": { "version": "20.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.2.tgz", "integrity": "sha512-5j/lXt7unfPOUlrKC34HIaedONleyLtwkKggiD/0uuMfT8gg2EOpg0dz4lCD15Ga7muC+1WzJZAjIB9simWd6Q==", "dev": true }, + "node_modules/webdriver/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/webdriver/node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/webdriver/node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/webdriver/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webdriver/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/webdriver/node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/webdriver/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webdriver/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webdriver/node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webdriver/node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/webdriver/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/webdriverio": { "version": "8.15.4", "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.15.4.tgz", @@ -34169,9 +34347,9 @@ } }, "@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "requires": { "regenerator-runtime": "^0.14.0" }, @@ -36206,11 +36384,11 @@ "integrity": "sha512-0aoWS4qvk1uzm9JBs83oQmIMIQeTBUeqqu8u+3uo2tMznrB5fIKqQVCbCgq+4Tm4jG+5F7dIvnjvQ2aV7UKtdw==" }, "@mui/icons-material": { - "version": "5.11.16", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.16.tgz", - "integrity": "sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==", + "version": "5.15.10", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.10.tgz", + "integrity": "sha512-9cF8oUHZKo9oQ7EQ3pxPELaZuZVmphskU4OI6NiJNDVN7zcuvrEsuWjYo1Zh4fLiC39Nrvm30h/B51rcUjvSGA==", "requires": { - "@babel/runtime": "^7.21.0" + "@babel/runtime": "^7.23.9" } }, "@mui/lab": { @@ -36892,12 +37070,6 @@ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" }, - "@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true - }, "@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", @@ -37030,15 +37202,6 @@ "loader-utils": "^2.0.0" } }, - "@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, "@testing-library/dom": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.14.0.tgz", @@ -37521,18 +37684,6 @@ "@types/node": "*" } }, - "@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, "@types/chai": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", @@ -38117,15 +38268,6 @@ "@types/node": "*" } }, - "@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/lodash": { "version": "4.14.182", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", @@ -38309,15 +38451,6 @@ "@types/node": "*" } }, - "@types/responselike": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", - "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", @@ -39061,11 +39194,121 @@ "wait-port": "^1.0.4" }, "dependencies": { + "@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true + }, + "cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + } + }, "decamelize": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", "dev": true + }, + "form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "got": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", + "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", + "dev": true, + "requires": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + } + }, + "http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true + }, + "normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "requires": { + "lowercase-keys": "^3.0.0" + } } } }, @@ -40355,27 +40598,6 @@ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true - }, - "cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - } - }, "call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -40717,15 +40939,6 @@ "wrap-ansi": "^7.0.0" } }, - "clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, "clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -44355,24 +44568,6 @@ "get-intrinsic": "^1.1.3" } }, - "got": { - "version": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", - "dev": true, - "requires": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -44980,16 +45175,6 @@ "sshpk": "^1.7.0" } }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - } - }, "https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -47562,12 +47747,6 @@ "tslib": "^2.0.3" } }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, "lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", @@ -48216,12 +48395,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, "min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -48791,12 +48964,6 @@ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true - }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -52309,15 +52476,6 @@ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==" }, - "responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, "resq": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/resq/-/resq-1.11.0.tgz", @@ -53693,6 +53851,14 @@ "requires": { "minimist": "^1.2.6" } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } } } }, @@ -55216,11 +55382,121 @@ "ws": "^8.8.0" }, "dependencies": { + "@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, "@types/node": { "version": "20.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.2.tgz", "integrity": "sha512-5j/lXt7unfPOUlrKC34HIaedONleyLtwkKggiD/0uuMfT8gg2EOpg0dz4lCD15Ga7muC+1WzJZAjIB9simWd6Q==", "dev": true + }, + "cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true + }, + "cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + } + }, + "form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + } + }, + "http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true + }, + "normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "requires": { + "lowercase-keys": "^3.0.0" + } } } }, diff --git a/package.json b/package.json index 82f783c812..d186483050 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@alkemio/client-web", - "version": "0.53.5", + "version": "0.53.6", "description": "Alkemio client, enabling users to interact with Challenges hosted on the Alkemio platform.", "author": "Alkemio Foundation", "repository": { @@ -34,7 +34,7 @@ "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", "@mui/base": "^5.0.0-beta.23", - "@mui/icons-material": "^5.11.16", + "@mui/icons-material": "^5.15.10", "@mui/lab": "^5.0.0-alpha.56", "@mui/material": "5.13.x", "@mui/styles": "^5.2.0", diff --git a/src/core/apollo/generated/apollo-hooks.ts b/src/core/apollo/generated/apollo-hooks.ts index 02a01aba51..e2ac010ac0 100644 --- a/src/core/apollo/generated/apollo-hooks.ts +++ b/src/core/apollo/generated/apollo-hooks.ts @@ -11140,21 +11140,6 @@ export const CommunityUserPrivilegesWithParentCommunityDocument = gql` } } } - adminUsers: usersInRole(role: ADMIN) { - id - profile { - id - displayName - avatar: visual(type: AVATAR) { - ...VisualUri - } - location { - id - country - city - } - } - } } } } diff --git a/src/core/apollo/generated/graphql-schema.ts b/src/core/apollo/generated/graphql-schema.ts index 5f911b7bd0..df208df373 100644 --- a/src/core/apollo/generated/graphql-schema.ts +++ b/src/core/apollo/generated/graphql-schema.ts @@ -17597,19 +17597,6 @@ export type CommunityUserPrivilegesWithParentCommunityQuery = { }; }> | undefined; - adminUsers?: - | Array<{ - __typename?: 'User'; - id: string; - profile: { - __typename?: 'Profile'; - id: string; - displayName: string; - avatar?: { __typename?: 'Visual'; id: string; uri: string; name: string } | undefined; - location?: { __typename?: 'Location'; id: string; country: string; city: string } | undefined; - }; - }> - | undefined; } | undefined; }; diff --git a/src/core/i18n/en/translation.en.json b/src/core/i18n/en/translation.en.json index 6c3f2e6428..29244192db 100644 --- a/src/core/i18n/en/translation.en.json +++ b/src/core/i18n/en/translation.en.json @@ -2281,7 +2281,8 @@ "whiteboardDisconnected": { "title": "Whiteboard connection lost", "message": "Apologies for the inconvenience! The whiteboard isn't available for editing right now, possibly due to a network issue or loss of access. Please try closing and reopening the whiteboard or refreshing the page. If the issue persists, reach out to your Space administrator for assistance.", - "lastSaved": "The content of this whiteboard was last saved {{lastSaved}}." + "lastSaved": "The content of this whiteboard was last saved {{lastSaved}}.", + "offline": "You are currently offline. The whiteboard will try to reconnect when you are back online." }, "readonlyReason": { "contentUpdatePolicy": "You don't have the rights to edit this whiteboard. Ask the owner, {{ownerName}}, to change the settings if you want to contribute.", diff --git a/src/domain/collaboration/whiteboard/WhiteboardDialog/WhiteboardRtDialog.tsx b/src/domain/collaboration/whiteboard/WhiteboardDialog/WhiteboardRtDialog.tsx index fd6a70c1fe..85db815812 100644 --- a/src/domain/collaboration/whiteboard/WhiteboardDialog/WhiteboardRtDialog.tsx +++ b/src/domain/collaboration/whiteboard/WhiteboardDialog/WhiteboardRtDialog.tsx @@ -11,7 +11,7 @@ import { DialogContent } from '../../../../core/ui/dialog/deprecated'; import CollaborativeExcalidrawWrapper from '../../../common/whiteboard/excalidraw/CollaborativeExcalidrawWrapper'; import { ExportedDataState } from '@alkemio/excalidraw/types/data/types'; import DialogHeader from '../../../../core/ui/dialog/DialogHeader'; -import { Box, Button, DialogActions } from '@mui/material'; +import { Box } from '@mui/material'; import { gutters } from '../../../../core/ui/grid/utils'; import whiteboardSchema from '../validation/whiteboardSchema'; import FormikInputField from '../../../../core/ui/forms/FormikInputField/FormikInputField'; @@ -25,12 +25,9 @@ import { generateWhiteboardPreviewImages, WhiteboardPreviewImage, } from '../WhiteboardPreviewImages/WhiteboardPreviewImages'; -import { Text } from '../../../../core/ui/typography'; -import { formatTimeElapsed } from '../../../shared/utils/formatTimeElapsed'; import { useWhiteboardRtLastUpdatedDateQuery } from '../../../../core/apollo/generated/apollo-hooks'; -import { CollabAPI } from '../../../common/whiteboard/excalidraw/collab/Collab'; +import { CollabAPI } from '../../../common/whiteboard/excalidraw/collab/useCollab'; import useWhiteboardFilesManager from '../../../common/whiteboard/excalidraw/useWhiteboardFilesManager'; -import WrapperMarkdown from '../../../../core/ui/markdown/WrapperMarkdown'; import WhiteboardDialogFooter from './WhiteboardDialogFooter'; import { useLocation } from 'react-router-dom'; import { ExcalidrawElement, ExcalidrawImageElement } from '@alkemio/excalidraw/types/element/types'; @@ -129,9 +126,7 @@ const WhiteboardRtDialog = ({ const [excalidrawAPI, setExcalidrawAPI] = useState(null); const collabApiRef = useRef(null); - const [collaborationEnabled, setCollaborationEnabled] = useState(true); - const [collaborationStoppedNoticeOpen, setCollaborationStoppedNoticeOpen] = useState(false); - const editModeEnabled = options.canEdit && collaborationEnabled; + const editModeEnabled = options.canEdit; const styles = useStyles(); @@ -226,7 +221,7 @@ const WhiteboardRtDialog = ({ }; const onClose = async () => { - if (editModeEnabled && collaborationEnabled && whiteboard) { + if (editModeEnabled && collabApiRef.current?.isCollaborating() && whiteboard) { const whiteboardState = await getWhiteboardState(); const { whiteboard: updatedWhiteboard, previewImages } = await prepareWhiteboardForUpdate( whiteboard, @@ -307,11 +302,9 @@ const WhiteboardRtDialog = ({ {!state?.loadingWhiteboardValue && whiteboard && ( ({ }); }, }} - events={{ - onCollaborationEnabledChange: enabled => { - setCollaborationEnabled(enabled); - setCollaborationStoppedNoticeOpen(!enabled); - }, - }} /> )} {state?.loadingWhiteboardValue && } @@ -358,22 +345,6 @@ const WhiteboardRtDialog = ({ )} - setCollaborationStoppedNoticeOpen(false)}> - - - {t('pages.whiteboard.whiteboardDisconnected.message')} - {lastSavedDate && ( - - {t('pages.whiteboard.whiteboardDisconnected.lastSaved', { - lastSaved: formatTimeElapsed(lastSavedDate, t), - })} - - )} - - - - - ); }; diff --git a/src/domain/common/whiteboard/excalidraw/CollaborativeExcalidrawWrapper.tsx b/src/domain/common/whiteboard/excalidraw/CollaborativeExcalidrawWrapper.tsx index 9e8fc47c69..89cad1f4df 100644 --- a/src/domain/common/whiteboard/excalidraw/CollaborativeExcalidrawWrapper.tsx +++ b/src/domain/common/whiteboard/excalidraw/CollaborativeExcalidrawWrapper.tsx @@ -7,10 +7,18 @@ import React, { Ref, useCallback, useEffect, useMemo, useRef, useState } from 'r import { useCombinedRefs } from '../../../shared/utils/useCombinedRefs'; import EmptyWhiteboard from '../EmptyWhiteboard'; import { ExcalidrawElement } from '@alkemio/excalidraw/types/element/types'; -import { CollabAPI } from './collab/Collab'; import { useUserContext } from '../../../community/user'; import { WhiteboardFilesManager } from './useWhiteboardFilesManager'; -import useCollab from './collab/useCollab'; +import useCollab, { CollabAPI } from './collab/useCollab'; +import Dialog from '@mui/material/Dialog'; +import DialogHeader from '../../../../core/ui/dialog/DialogHeader'; +import { DialogContent } from '../../../../core/ui/dialog/deprecated'; +import WrapperMarkdown from '../../../../core/ui/markdown/WrapperMarkdown'; +import { Text } from '../../../../core/ui/typography'; +import { formatTimeElapsed } from '../../../shared/utils/formatTimeElapsed'; +import { Button, DialogActions } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { LoadingButton } from '@mui/lab'; const useActorWhiteboardStyles = makeStyles(theme => ({ container: { @@ -30,6 +38,7 @@ const useActorWhiteboardStyles = makeStyles(theme => ({ export interface WhiteboardWhiteboardEntities { whiteboard: { id?: string; content: string } | undefined; filesManager: WhiteboardFilesManager; + lastSavedDate: Date | undefined; } export interface WhiteboardWhiteboardActions { @@ -38,32 +47,22 @@ export interface WhiteboardWhiteboardActions { onSavedToDatabase?: () => void; } -export interface WhiteboardWhiteboardEvents { - onCollaborationEnabledChange?: (collaborationEnabled: boolean) => void; -} +export interface WhiteboardWhiteboardEvents {} -export interface WhiteboardWhiteboardOptions extends ExcalidrawProps { - collaborationEnabled: boolean; -} +export interface WhiteboardWhiteboardOptions extends ExcalidrawProps {} export interface WhiteboardWhiteboardProps { entities: WhiteboardWhiteboardEntities; options: WhiteboardWhiteboardOptions; actions: WhiteboardWhiteboardActions; - events: WhiteboardWhiteboardEvents; + events?: WhiteboardWhiteboardEvents; collabApiRef?: Ref; } const WINDOW_SCROLL_HANDLER_DEBOUNCE_INTERVAL = 100; -const CollaborativeExcalidrawWrapper = ({ - entities, - actions, - options, - events, - collabApiRef, -}: WhiteboardWhiteboardProps) => { - const { whiteboard, filesManager } = entities; +const CollaborativeExcalidrawWrapper = ({ entities, actions, options, collabApiRef }: WhiteboardWhiteboardProps) => { + const { whiteboard, filesManager, lastSavedDate } = entities; const combinedCollabApiRef = useCombinedRefs(null, collabApiRef); @@ -116,11 +115,11 @@ const CollaborativeExcalidrawWrapper = ({ [] ); - const { UIOptions: externalUIOptions, collaborationEnabled, ...restOptions } = options; + const { UIOptions: externalUIOptions, ...restOptions } = options; const mergedUIOptions = useMemo(() => merge(UIOptions, externalUIOptions), [UIOptions, externalUIOptions]); - const [collabApi, initializeCollab] = useCollab({ + const [collabApi, initializeCollab, { connecting, collaborating }] = useCollab({ username, onSavedToDatabase: actions.onSavedToDatabase, filesManager, @@ -138,11 +137,10 @@ const CollaborativeExcalidrawWrapper = ({ return { success: false, errors: ['ExcalidrawAPI not yet ready'] }; }, onCloseConnection: () => { - events.onCollaborationEnabledChange?.(false); + setCollaborationStoppedNoticeOpen(true); }, onInitialize: collabApi => { combinedCollabApiRef.current = collabApi; - events.onCollaborationEnabledChange?.(true); }, }); @@ -153,14 +151,26 @@ const CollaborativeExcalidrawWrapper = ({ const [excalidrawApi, setExcalidrawApi] = useState(null); + const [collaborationStartTime, setCollaborationStartTime] = useState(Date.now()); + + const restartCollaboration = () => { + setCollaborationStartTime(Date.now()); + }; + + useEffect(() => { + if (!connecting && collaborating) { + setCollaborationStoppedNoticeOpen(false); + } + }, [connecting, collaborating]); + useEffect(() => { - if (excalidrawApi && whiteboard?.id) { + if (excalidrawApi && whiteboard?.id && collaborationStartTime !== null) { return initializeCollab({ excalidrawApi, roomId: whiteboard.id, }); } - }, [excalidrawApi, whiteboard?.id]); + }, [excalidrawApi, whiteboard?.id, collaborationStartTime]); const handleInitializeApi = useCallback( (excalidrawApi: ExcalidrawImperativeAPI) => { @@ -170,29 +180,68 @@ const CollaborativeExcalidrawWrapper = ({ [actions.onInitApi] ); + const [collaborationStoppedNoticeOpen, setCollaborationStoppedNoticeOpen] = useState(false); + + const { t } = useTranslation(); + + const [isOnline, setIsOnline] = useState(navigator.onLine); + + useEffect(() => { + const handleOnlineChange = () => setIsOnline(navigator.onLine); + window.addEventListener('online', handleOnlineChange); + window.addEventListener('offline', handleOnlineChange); + setIsOnline(navigator.onLine); + return () => { + window.removeEventListener('online', handleOnlineChange); + window.removeEventListener('offline', handleOnlineChange); + }; + }, []); + return ( -
- {whiteboard && ( - { - return ; - }}*/ - {...restOptions} - /> - )} -
+ <> +
+ {whiteboard && ( + { + return ; + }}*/ + {...restOptions} + /> + )} +
+ setCollaborationStoppedNoticeOpen(false)}> + + + {isOnline && {t('pages.whiteboard.whiteboardDisconnected.message')}} + {!isOnline && {t('pages.whiteboard.whiteboardDisconnected.offline')}} + {lastSavedDate && ( + + {t('pages.whiteboard.whiteboardDisconnected.lastSaved', { + lastSaved: formatTimeElapsed(lastSavedDate, t), + })} + + )} + + + + Reconnect + + + + + ); }; diff --git a/src/domain/common/whiteboard/excalidraw/collab/Collab.ts b/src/domain/common/whiteboard/excalidraw/collab/Collab.ts index 71cc8a81b0..dcae184fbf 100644 --- a/src/domain/common/whiteboard/excalidraw/collab/Collab.ts +++ b/src/domain/common/whiteboard/excalidraw/collab/Collab.ts @@ -5,11 +5,9 @@ import { CURSOR_SYNC_TIMEOUT, EVENT, IDLE_THRESHOLD, - INITIAL_SCENE_UPDATE_TIMEOUT, SYNC_FULL_SCENE_INTERVAL_MS, WS_SCENE_EVENT_TYPES, } from './excalidrawAppConstants'; -import { ImportedDataState } from '@alkemio/excalidraw/types/data/types'; import { ExcalidrawElement } from '@alkemio/excalidraw/types/element/types'; import { getSceneVersion, newElementWith, restoreElements } from '@alkemio/excalidraw'; import { isImageElement, UserIdleState } from './utils'; @@ -24,17 +22,6 @@ interface CollabState { activeRoomLink: string; } -type CollabInstance = InstanceType; - -export interface CollabAPI { - /** function so that we can access the latest value from stale callbacks */ - onPointerUpdate: CollabInstance['onPointerUpdate']; - startCollaboration: CollabInstance['startCollaboration']; - stopCollaboration: CollabInstance['stopCollaboration']; - syncScene: CollabInstance['syncScene']; - notifySavedToDatabase: () => void; // Notify rest of the members in the room that I have saved the whiteboard -} - export interface CollabProps { excalidrawApi: ExcalidrawImperativeAPI; username: string; @@ -77,16 +64,8 @@ class Collab { this.onSavedToDatabase = props.onSavedToDatabase; } - init(): CollabAPI { + init() { window.addEventListener(EVENT.UNLOAD, this.onUnload); - - return { - onPointerUpdate: this.onPointerUpdate, - startCollaboration: this.startCollaboration, - syncScene: this.syncScene, - stopCollaboration: this.stopCollaboration, - notifySavedToDatabase: this.notifySavedToDatabase, - }; } destroy() { @@ -117,10 +96,6 @@ class Collab { stopCollaboration = () => { this.queueBroadcastAllElements.cancel(); - if (this.portal.socket && this.fallbackInitializationHandler) { - this.portal.socket.off('connect_error', this.fallbackInitializationHandler); - } - this.destroySocketClient(); const elements = this.excalidrawAPI.getSceneElementsIncludingDeleted().map(element => { @@ -136,6 +111,10 @@ class Collab { }); }; + public isCollaborating = () => { + return this.portal.isOpen(); + }; + private destroySocketClient = (opts?: { isUnload: boolean }) => { this.lastBroadcastedOrReceivedSceneVersion = -1; this.portal.close(); @@ -149,149 +128,100 @@ class Collab { } }; - private fallbackInitializationHandler: null | (() => unknown) = null; - - startCollaboration = async (existingRoomLinkData: { roomId: string }): Promise => - new Promise(async resolve => { - if (this.portal.socket) { - return null; - } - + startCollaboration = async (existingRoomLinkData: { roomId: string }): Promise => + new Promise(async (resolve, reject) => { const { roomId } = existingRoomLinkData; - const { default: socketIOClient } = await import('socket.io-client'); - - const fallbackInitializationHandler = () => { - this.initializeRoom({ - roomLinkData: existingRoomLinkData, - fetchScene: true, - }).then(scene => { - resolve(scene); - }); - }; - - this.fallbackInitializationHandler = fallbackInitializationHandler; - try { const socketServerData = await getCollabServer(); - this.portal.socket = this.portal.open( - socketIOClient(socketServerData.url, { - transports: socketServerData.polling ? ['websocket', 'polling'] : ['websocket'], - path: '/api/private/ws/socket.io', - }), - roomId - ); + await this.portal.open( + { + ...socketServerData, + roomId, + }, + { + 'client-broadcast': async (encryptedData: ArrayBuffer) => { + const decodedData = new TextDecoder().decode(encryptedData); + const decryptedData = JSON.parse(decodedData); + + switch (decryptedData.type) { + case 'INVALID_RESPONSE': + return; + case WS_SCENE_EVENT_TYPES.INIT: { + if (!this.portal.socketInitialized) { + this.initializeRoom({ fetchScene: false }); + const remoteElements = decryptedData.payload.elements; + const remoteFiles = decryptedData.payload.files; + this.handleRemoteSceneUpdate(this.reconcileElements(remoteElements, remoteFiles), { + init: true, + }); + } + resolve(); + break; + } + case WS_SCENE_EVENT_TYPES.SCENE_UPDATE: { + const remoteElements = decryptedData.payload.elements; + const remoteFiles = decryptedData.payload.files; + this.handleRemoteSceneUpdate(this.reconcileElements(remoteElements, remoteFiles)); + break; + } + + case WS_SCENE_EVENT_TYPES.MOUSE_LOCATION: { + const { pointer, button, username, selectedElementIds } = decryptedData.payload; + const socketId: SocketUpdateDataSource['MOUSE_LOCATION']['payload']['socketId'] = + decryptedData.payload.socketId || + // @ts-ignore legacy, see #2094 (#2097) + decryptedData.payload.socketID; + + const collaborators = new Map(this.collaborators); + const user = collaborators.get(socketId) || {}!; + user.pointer = pointer; + user.button = button; + user.selectedElementIds = selectedElementIds; + user.username = username; + collaborators.set(socketId, user); + this.excalidrawAPI.updateScene({ + collaborators, + }); + break; + } + + case WS_SCENE_EVENT_TYPES.IDLE_STATUS: { + const { userState, socketId, username } = decryptedData.payload; + const collaborators = new Map(this.collaborators); + const user = collaborators.get(socketId) || {}!; + user.userState = userState; + user.username = username; + this.excalidrawAPI.updateScene({ + collaborators, + }); + break; + } + + case WS_SCENE_EVENT_TYPES.SAVED: { + this.onSavedToDatabase?.(); + break; + } + } + }, + 'first-in-room': async () => { + await this.initializeRoom({ + fetchScene: true, + roomLinkData: existingRoomLinkData, + }); - this.portal.socket.once('connect_error', fallbackInitializationHandler); + resolve(); + }, + } + ); } catch (error) { // eslint-disable-next-line no-console console.error(error); this.state.errorMessage = (error as { message: string } | undefined)?.message ?? ''; - return null; + reject(error); } - if (!existingRoomLinkData) { - const elements = this.excalidrawAPI.getSceneElements().map(element => { - if (isImageElement(element) && element.status === 'saved') { - return newElementWith(element, { status: 'pending' }); - } - - return element; - }); - // remove deleted elements from elements array & history to ensure we don't - // expose potentially sensitive user data in case user manually deletes - // existing elements (or clears scene), which would otherwise be persisted - // to database even if deleted before creating the room. - this.excalidrawAPI.history.clear(); - this.excalidrawAPI.updateScene({ - elements, - commitToHistory: true, - }); - } - - // fallback in case you're not alone in the room but still don't receive - // initial SCENE_INIT message - this.socketInitializationTimer = window.setTimeout(fallbackInitializationHandler, INITIAL_SCENE_UPDATE_TIMEOUT); - - // All socket listeners are moving to Portal - this.portal.socket.on('client-broadcast', async (encryptedData: ArrayBuffer) => { - const decodedData = new TextDecoder().decode(encryptedData); - const decryptedData = JSON.parse(decodedData); - - switch (decryptedData.type) { - case 'INVALID_RESPONSE': - return; - case WS_SCENE_EVENT_TYPES.INIT: { - if (!this.portal.socketInitialized) { - this.initializeRoom({ fetchScene: false }); - const remoteElements = decryptedData.payload.elements; - const remoteFiles = decryptedData.payload.files; - this.handleRemoteSceneUpdate(this.reconcileElements(remoteElements, remoteFiles), { - init: true, - }); - } - break; - } - - case WS_SCENE_EVENT_TYPES.SCENE_UPDATE: { - const remoteElements = decryptedData.payload.elements; - const remoteFiles = decryptedData.payload.files; - this.handleRemoteSceneUpdate(this.reconcileElements(remoteElements, remoteFiles)); - break; - } - - case WS_SCENE_EVENT_TYPES.MOUSE_LOCATION: { - const { pointer, button, username, selectedElementIds } = decryptedData.payload; - const socketId: SocketUpdateDataSource['MOUSE_LOCATION']['payload']['socketId'] = - decryptedData.payload.socketId || - // @ts-ignore legacy, see #2094 (#2097) - decryptedData.payload.socketID; - - const collaborators = new Map(this.collaborators); - const user = collaborators.get(socketId) || {}!; - user.pointer = pointer; - user.button = button; - user.selectedElementIds = selectedElementIds; - user.username = username; - collaborators.set(socketId, user); - this.excalidrawAPI.updateScene({ - collaborators, - }); - break; - } - - case WS_SCENE_EVENT_TYPES.IDLE_STATUS: { - const { userState, socketId, username } = decryptedData.payload; - const collaborators = new Map(this.collaborators); - const user = collaborators.get(socketId) || {}!; - user.userState = userState; - user.username = username; - this.excalidrawAPI.updateScene({ - collaborators, - }); - break; - } - - case WS_SCENE_EVENT_TYPES.SAVED: { - this.onSavedToDatabase?.(); - break; - } - } - }); - - this.portal.socket.on('first-in-room', async () => { - if (this.portal.socket) { - this.portal.socket.off('first-in-room'); - } - - const sceneData = await this.initializeRoom({ - fetchScene: true, - roomLinkData: existingRoomLinkData, - }); - resolve(sceneData); - }); - this.initializeIdleDetector(); this.state.activeRoomLink = window.location.href; @@ -308,11 +238,7 @@ class Collab { | { fetchScene: false; roomLinkData?: null }) => { clearTimeout(this.socketInitializationTimer!); - if (this.portal.socket && this.fallbackInitializationHandler) { - this.portal.socket.off('connect_error', this.fallbackInitializationHandler); - } - - if (fetchScene && roomLinkData && this.portal.socket) { + if (fetchScene && roomLinkData) { try { this.queueBroadcastAllElements(); } catch (error: unknown) { @@ -325,8 +251,6 @@ class Collab { } else { this.portal.socketInitialized = true; } - - return null; }; private reconcileElements = ( @@ -419,7 +343,7 @@ class Collab { }; private setCollaborators = (sockets: string[]) => { - const collaborators: InstanceType['collaborators'] = new Map(); + const collaborators = new Map(); for (const socketId of sockets) { if (this.collaborators.has(socketId)) { @@ -449,7 +373,7 @@ class Collab { return this.filesManager.getUploadedFiles(this.excalidrawAPI.getFiles()); }; - private onPointerUpdate = throttle( + public onPointerUpdate = throttle( (payload: { pointer: SocketUpdateDataSource['MOUSE_LOCATION']['payload']['pointer']; button: SocketUpdateDataSource['MOUSE_LOCATION']['payload']['button']; @@ -470,7 +394,7 @@ class Collab { this.portal.broadcastIdleChange(userState, this.state.username); }; - private syncScene = async (elements: readonly ExcalidrawElement[], files: BinaryFilesWithUrl) => { + public syncScene = async (elements: readonly ExcalidrawElement[], files: BinaryFilesWithUrl) => { if (getSceneVersion(elements) > this.getLastBroadcastedOrReceivedSceneVersion()) { this.portal.broadcastScene(WS_SCENE_EVENT_TYPES.SCENE_UPDATE, elements, files, { syncAll: false }); this.lastBroadcastedOrReceivedSceneVersion = getSceneVersion(elements); @@ -478,7 +402,7 @@ class Collab { } }; - private notifySavedToDatabase = () => { + public notifySavedToDatabase = () => { this.portal.broadcastSavedEvent(this.state.username); }; diff --git a/src/domain/common/whiteboard/excalidraw/collab/Portal.ts b/src/domain/common/whiteboard/excalidraw/collab/Portal.ts index a366663483..46fdae0189 100644 --- a/src/domain/common/whiteboard/excalidraw/collab/Portal.ts +++ b/src/domain/common/whiteboard/excalidraw/collab/Portal.ts @@ -23,6 +23,17 @@ interface BroadcastSceneOptions { syncAll?: boolean; } +interface ConnectionOptions { + url: string; + roomId: string; + polling?: boolean; +} + +interface SocketEventHandlers { + 'client-broadcast': (encryptedData: ArrayBuffer) => void; + 'first-in-room': () => void; +} + class Portal { onSaveRequest: () => Promise<{ success: boolean; errors?: string[] }>; onCloseConnection: () => void; @@ -43,39 +54,74 @@ class Portal { this.onCloseConnection = onCloseConnection; } - open(socket: Socket, id: string) { - this.socket = socket; - this.roomId = id; + open(connectionOptions: ConnectionOptions, eventHandlers: SocketEventHandlers) { + if (this.socket) { + throw new Error('Socket already open'); + } - // Initialize socket listeners - this.socket.on('init-room', () => { - if (this.socket) { - this.socket.emit('join-room', this.roomId); - } - }); + return new Promise(async (resolve, reject) => { + const { default: socketIOClient } = await import('socket.io-client'); - this.socket.on('new-user', async (_socketId: string) => { - this.broadcastScene(WS_SCENE_EVENT_TYPES.INIT, this.getSceneElements(), await this.getFiles(), { syncAll: true }); - }); + const socket = socketIOClient(connectionOptions.url, { + transports: connectionOptions.polling ? ['websocket', 'polling'] : ['websocket'], + path: '/api/private/ws/socket.io', + retries: 0, + reconnection: false, + }); - this.socket.on('room-user-change', (clients: string[]) => { - this.onRoomUserChange(clients); - }); + this.socket = socket; + this.roomId = connectionOptions.roomId; - this.socket.on('save-request', async callback => { - try { - callback(await this.onSaveRequest()); - } catch (ex) { - callback({ success: false, errors: [(ex as { message?: string })?.message ?? ex] }); - } - }); + // Initialize socket listeners + this.socket.on('init-room', () => { + if (this.socket) { + this.socket.emit('join-room', this.roomId); + } + }); - this.socket.on('disconnect', () => { - this.close(); - this.onCloseConnection(); - }); + this.socket.on('new-user', async (_socketId: string) => { + this.broadcastScene(WS_SCENE_EVENT_TYPES.INIT, this.getSceneElements(), await this.getFiles(), { syncAll: true }); + }); + + this.socket.on('room-user-change', (clients: string[]) => { + this.onRoomUserChange(clients); + }); + + this.socket.on('save-request', async callback => { + try { + callback(await this.onSaveRequest()); + } catch (ex) { + callback({ success: false, errors: [(ex as { message?: string })?.message ?? ex] }); + } + }); + + this.socket.on('client-broadcast', eventHandlers['client-broadcast']); - return socket; + this.socket.on('first-in-room', () => { + socket.off('first-in-room'); + eventHandlers['first-in-room'](); + }); + + this.socket.on('connect', () => { + resolve(socket); + }); + + this.socket.on('connect_error', () => { + reject(new Error('Socket could not connect')); + this.close(); + this.onCloseConnection(); + }); + + this.socket.on('disconnect', reason => { + if (reason === 'io client disconnect') { + // disconnected intentionally + return; + } + reject(new Error('Socket disconnected')); + this.close(); + this.onCloseConnection(); + }); + }); } close() { diff --git a/src/domain/common/whiteboard/excalidraw/collab/excalidrawAppConstants.ts b/src/domain/common/whiteboard/excalidraw/collab/excalidrawAppConstants.ts index baf115a1f6..89d7b6df6d 100644 --- a/src/domain/common/whiteboard/excalidraw/collab/excalidrawAppConstants.ts +++ b/src/domain/common/whiteboard/excalidraw/collab/excalidrawAppConstants.ts @@ -39,7 +39,6 @@ export const ACTIVE_THRESHOLD = 3_000; // time constants (ms) export const SAVE_TO_LOCAL_STORAGE_TIMEOUT = 300; -export const INITIAL_SCENE_UPDATE_TIMEOUT = 5000; export const FILE_UPLOAD_TIMEOUT = 300; export const LOAD_IMAGES_TIMEOUT = 500; export const SYNC_FULL_SCENE_INTERVAL_MS = 20000; diff --git a/src/domain/common/whiteboard/excalidraw/collab/useCollab.ts b/src/domain/common/whiteboard/excalidraw/collab/useCollab.ts index 998d50666d..6f70a2e2a6 100644 --- a/src/domain/common/whiteboard/excalidraw/collab/useCollab.ts +++ b/src/domain/common/whiteboard/excalidraw/collab/useCollab.ts @@ -1,7 +1,17 @@ -import { useRef } from 'react'; -import Collab, { CollabAPI, CollabProps } from './Collab'; +import { useRef, useState } from 'react'; +import Collab, { CollabProps } from './Collab'; -type UseCollabProvided = [CollabAPI | null, (initProps: InitProps) => void]; +type CollabInstance = InstanceType; + +export interface CollabAPI { + /** function so that we can access the latest value from stale callbacks */ + onPointerUpdate: CollabInstance['onPointerUpdate']; + syncScene: CollabInstance['syncScene']; + notifySavedToDatabase: () => void; // Notify rest of the members in the room that I have saved the whiteboard + isCollaborating: () => boolean; +} + +type UseCollabProvided = [CollabAPI | null, (initProps: InitProps) => void, CollabState]; interface UseCollabProps extends Omit { onInitialize?: (collabApi: CollabAPI) => void; @@ -11,28 +21,66 @@ interface InitProps extends Pick { roomId: string; } -const useCollab = ({ onInitialize, ...collabProps }: UseCollabProps): UseCollabProvided => { +interface CollabState { + collaborating: boolean; + connecting: boolean; +} + +const useCollab = ({ onInitialize, onCloseConnection, ...collabProps }: UseCollabProps): UseCollabProvided => { const collabRef = useRef(null); const collabApiRef = useRef(null); + const [isConnecting, setIsConnecting] = useState(false); + + const [isCollaborating, setIsCollaborating] = useState(false); + + const handleCloseConnection = () => { + try { + onCloseConnection(); + } finally { + setIsCollaborating(false); + } + }; + const initialize = ({ excalidrawApi, roomId }: InitProps) => { collabRef.current = new Collab({ ...collabProps, excalidrawApi, + onCloseConnection: handleCloseConnection, }); - const collabApi = collabRef.current.init(); - collabApi.startCollaboration({ roomId }); + + collabRef.current.init(); + + const collabApi: CollabAPI = { + onPointerUpdate: collabRef.current.onPointerUpdate, + syncScene: collabRef.current.syncScene, + notifySavedToDatabase: collabRef.current.notifySavedToDatabase, + isCollaborating: collabRef.current.isCollaborating, + }; + + (async () => { + setIsConnecting(true); + try { + await collabRef.current?.startCollaboration({ roomId }); + setIsCollaborating(true); + } finally { + setIsConnecting(false); + } + })(); + collabApiRef.current = collabApi; + onInitialize?.(collabApi); return () => { + collabRef.current?.stopCollaboration(); collabRef.current?.destroy(); collabApiRef.current = null; }; }; - return [collabApiRef.current, initialize]; + return [collabApiRef.current, initialize, { connecting: isConnecting, collaborating: isCollaborating }]; }; export default useCollab; diff --git a/src/domain/community/application/applicationButton/OpportunityApplicationButton.tsx b/src/domain/community/application/applicationButton/OpportunityApplicationButton.tsx index a009636f5c..1211f75078 100644 --- a/src/domain/community/application/applicationButton/OpportunityApplicationButton.tsx +++ b/src/domain/community/application/applicationButton/OpportunityApplicationButton.tsx @@ -1,17 +1,17 @@ import { Button as MuiButton, CircularProgress } from '@mui/material'; -import React, { forwardRef, Ref } from 'react'; +import React, { forwardRef, Ref, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Link as RouterLink } from 'react-router-dom'; import { buildLoginUrl } from '../../../../main/routing/urlBuilders'; import { AddOutlined } from '@mui/icons-material'; -import RootThemeProvider from '../../../../core/ui/themes/RootThemeProvider'; -import useDirectMessageDialog from '../../../communication/messaging/DirectMessaging/useDirectMessageDialog'; +import { DirectMessageDialog } from '../../../communication/messaging/DirectMessaging/DirectMessageDialog'; export interface OpportunityApplicationButtonProps { isAuthenticated?: boolean; isMember: boolean; isParentMember?: boolean; parentUrl?: string; + sendMessageToCommunityLeads: (message: string) => Promise; leadUsers: { id: string; displayName?: string; @@ -19,13 +19,6 @@ export interface OpportunityApplicationButtonProps { country?: string; avatarUri?: string; }[]; - adminUsers: { - id: string; - displayName?: string; - city?: string; - country?: string; - avatarUri?: string; - }[]; loading: boolean; component?: typeof MuiButton; extended?: boolean; @@ -41,8 +34,8 @@ export const OpportunityApplicationButton = forwardRef< isMember = false, isParentMember = false, parentUrl, + sendMessageToCommunityLeads, leadUsers, - adminUsers, loading = false, component: Button = MuiButton, extended = false, @@ -50,14 +43,12 @@ export const OpportunityApplicationButton = forwardRef< ref ) => { const { t } = useTranslation(); - const { sendMessage, directMessageDialog } = useDirectMessageDialog({ - dialogTitle: t('send-message-dialog.direct-message-title'), - }); - - const contactUsers = leadUsers.length > 0 ? leadUsers : adminUsers; - - const handleSendMessageToParentLeads = () => { - sendMessage('user', ...contactUsers); + const [isContactLeadUsersDialogOpen, setIsContactLeadUsersDialogOpen] = useState(false); + const openContactLeadsDialog = () => { + setIsContactLeadUsersDialogOpen(true); + }; + const closeContactLeadsDialog = () => { + setIsContactLeadUsersDialogOpen(false); }; const renderApplicationButton = () => { @@ -99,29 +90,33 @@ export const OpportunityApplicationButton = forwardRef< ); } - if (contactUsers.length === 0) { + if (leadUsers.length === 0) { return null; } return ( - + <> + + + ); }; - return ( - <> - {renderApplicationButton()} - {directMessageDialog} - - ); + return <>{renderApplicationButton()}; } ); diff --git a/src/domain/community/application/containers/OpportunityApplicationButtonContainer.tsx b/src/domain/community/application/containers/OpportunityApplicationButtonContainer.tsx index 9afcc5073f..e46618ffdc 100644 --- a/src/domain/community/application/containers/OpportunityApplicationButtonContainer.tsx +++ b/src/domain/community/application/containers/OpportunityApplicationButtonContainer.tsx @@ -8,6 +8,7 @@ import { CommunityMembershipStatus } from '../../../../core/apollo/generated/gra import { useCommunityContext } from '../../community/CommunityContext'; import { useAuthenticationContext } from '../../../../core/auth/authentication/hooks/useAuthenticationContext'; import { SimpleContainerProps } from '../../../../core/container/SimpleContainer'; +import useSendMessageToCommunityLeads from '../../CommunityLeads/useSendMessageToCommunityLeads'; interface ApplicationContainerState { loading: boolean; @@ -48,7 +49,6 @@ export const OpportunityApplicationButtonContainer: FC ({ id: user.id, displayName: user.profile.displayName, @@ -56,13 +56,8 @@ export const OpportunityApplicationButtonContainer: FC ({ - id: user.id, - displayName: user.profile.displayName, - country: user.profile.location?.country, - city: user.profile.location?.city, - avatarUri: user.profile.avatar?.uri, - })); + const communityId = _communityPrivileges?.space.opportunity?.community?.id; + const sendMessageToCommunityLeads = useSendMessageToCommunityLeads(communityId); const loading = communityPrivilegesLoading; @@ -70,8 +65,8 @@ export const OpportunityApplicationButtonContainer: FC = ({ entities: { userMetadata } }) => { const { t } = useTranslation(); const { user, keywords, skills } = userMetadata; const references = user.profile.references; const bio = user.profile.description; - - const nonSocialReferences = useMemo(() => { - return references?.filter(x => !isSocialNetworkSupported(x.name)); + const links = useMemo(() => { + return groupBy(references, reference => + isSocialNetworkSupported(reference.name) ? SOCIAL_LINK_GROUP : OTHER_LINK_GROUP + ); }, [references]); + const socialLinks = links[SOCIAL_LINK_GROUP].map(s => ({ + type: s.name as SocialNetworkEnum, + url: s.uri, + })); + return ( @@ -50,10 +64,13 @@ export const UserProfileView: FC = ({ entities: { userMeta {t('components.profile.fields.links.title')} {t('common.no-references')}} /> + + + ); }; diff --git a/src/domain/shared/components/SocialLinks/SocialLinks.tsx b/src/domain/shared/components/SocialLinks/SocialLinks.tsx index e3d090048c..21be5529ba 100644 --- a/src/domain/shared/components/SocialLinks/SocialLinks.tsx +++ b/src/domain/shared/components/SocialLinks/SocialLinks.tsx @@ -6,15 +6,12 @@ import WrapperTypography from '../../../../core/ui/typography/deprecated/Wrapper import GitHub from './icons/GitHub'; import LinkedIn from './icons/LinkedIn'; import Twitter from './icons/Twitter'; -import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; import * as yup from 'yup'; interface SocialLinksProps { title?: string; items?: SocialLinkItem[]; iconSize?: SvgIconProps['fontSize']; - isContactable: boolean; - onContact: () => void; } const getSocialIcon = (type: SocialNetworkEnum, fontSize: SvgIconProps['fontSize'] = 'large') => { @@ -52,7 +49,7 @@ export interface SocialLinkItem { const schema = yup.string().url(); -export const SocialLinks: FC = ({ title, items, iconSize, isContactable, onContact }) => { +export const SocialLinks: FC = ({ title, items, iconSize }) => { const filteredSortedItems = useMemo( () => items @@ -79,17 +76,6 @@ export const SocialLinks: FC = ({ title, items, iconSize, isCo {getSocialIcon(item.type, iconSize)} ))} - - {isContactable && ( - - - - )} ); }; diff --git a/src/domain/shared/components/SocialLinks/icons/Twitter.tsx b/src/domain/shared/components/SocialLinks/icons/Twitter.tsx index b428fcab39..5f81599152 100644 --- a/src/domain/shared/components/SocialLinks/icons/Twitter.tsx +++ b/src/domain/shared/components/SocialLinks/icons/Twitter.tsx @@ -1,9 +1,9 @@ -import { Twitter as MUITwitter } from '@mui/icons-material'; +import { X as MUIX } from '@mui/icons-material'; import { SvgIconProps } from '@mui/material'; import React, { FC } from 'react'; const Twitter: FC = props => { - return ; + return ; }; export default Twitter;