From a32ad2f4a33bec71ce4cc7bc0e0a3bbd233de46c Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 30 Sep 2026 16:22:00 +0200 Subject: [PATCH 01/50] feat: NethVoice chat chat-island in its own always-on-top window, like the phone island; Chat menu with the conversations and new chat; nethlink://chat?to= opens a conversation. --- package-lock.json | 1768 +++++++++++++---- package.json | 1 + public/locales/en/translations.json | 6 + public/locales/it/translations.json | 6 + src/main/classes/controllers/AppController.ts | 6 + .../controllers/ChatIslandController.ts | 54 + src/main/classes/controllers/index.ts | 1 + src/main/classes/windows/ChatIslandWindow.ts | 42 + src/main/classes/windows/index.ts | 1 + src/main/lib/ipcEvents.ts | 31 + src/main/main.ts | 13 + src/renderer/src/App.tsx | 8 + .../Modules/NethVoice/BaseModule/Sidebar.tsx | 13 + .../Modules/NethVoice/Chat/ChatModule.tsx | 81 + .../components/Modules/NethlinkModules.tsx | 3 + src/renderer/src/hooks/useChatBridge.ts | 50 + src/renderer/src/pages/ChatIslandPage.tsx | 125 ++ src/renderer/src/pages/NethLinkPage.tsx | 2 + src/renderer/src/store.ts | 3 + src/shared/constants.ts | 4 + src/shared/types.ts | 15 + 21 files changed, 1883 insertions(+), 350 deletions(-) create mode 100644 src/main/classes/controllers/ChatIslandController.ts create mode 100644 src/main/classes/windows/ChatIslandWindow.ts create mode 100644 src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx create mode 100644 src/renderer/src/hooks/useChatBridge.ts create mode 100644 src/renderer/src/pages/ChatIslandPage.tsx diff --git a/package-lock.json b/package-lock.json index d6a64a4a..10f91db3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "win-ca": "^3.5.1" }, "devDependencies": { + "@date-fns/utc": "^2.0.0", "@electron-toolkit/eslint-config-prettier": "^3.0.0", "@electron-toolkit/eslint-config-ts": "^3.1.0", "@electron-toolkit/preload": "^3.0.0", @@ -27,6 +28,9 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", + "@nethesis/chat-island": "^0.1.2", + "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", + "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", @@ -35,10 +39,12 @@ "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.2.1", + "auto-launch": "^5.0.6", "autoprefixer": "^10.4.17", "axios": "^1.6.7", "classnames": "^2.5.1", "clsx": "^2.1.0", + "crypto-browserify": "^3.12.0", "crypto-js": "^4.2.0", "date-fns": "^2.30.0", "date-fns-tz": "^1.3.8", @@ -51,10 +57,13 @@ "eslint-plugin-react-hooks": "^5.2.0", "framer-motion": "^11.11.8", "i18next": "^22.4.9", + "i18next-browser-languagedetector": "^7.0.1", "i18next-electron-fs-backend": "^3.0.1", "i18next-fs-backend": "^2.3.2", + "i18next-http-backend": "^2.1.1", "lodash": "^4.17.21", "moment": "^2.30.1", + "motion": "^11.13.1", "path-browserify": "^1.0.1", "postcss": "^8.4.35", "prettier": "^3.2.4", @@ -64,11 +73,13 @@ "react-hook-form": "^7.50.1", "react-i18next": "^12.1.5", "react-router-dom": "^6.21.3", - "react-tooltip": "^5.28.0", + "rollup": "^4.12.1", "tailwind-merge": "^2.2.1", + "tailwind-scrollbar": "^3.1.0", "tailwindcss": "^3.4.1", "typescript": "^5.3.3", "vite": "^5.0.12", + "vite-plugin-copy": "^0.1.6", "zod": "^3.22.4", "zustand": "^4.5.0" }, @@ -97,13 +108,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -112,9 +123,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", "dev": true, "license": "MIT", "engines": { @@ -122,21 +133,21 @@ } }, "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -163,14 +174,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", - "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.8", - "@babel/types": "^7.29.8", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -193,14 +204,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -220,9 +231,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, "license": "MIT", "engines": { @@ -230,29 +241,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -272,9 +283,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -282,9 +293,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -292,9 +303,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -302,27 +313,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.29.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.10.tgz", - "integrity": "sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.8" + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", - "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.8" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -406,33 +417,33 @@ } }, "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.10.tgz", - "integrity": "sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.8", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.9", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.8", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -440,19 +451,26 @@ } }, "node_modules/@babel/types": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", - "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@date-fns/utc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@date-fns/utc/-/utc-2.1.1.tgz", + "integrity": "sha512-SlJDfG6RPeEX8wEVv6ZB3kak4MmbtyiI2qX/5zuKdordbrhB/iaJ58GVMZgJ6P1sJaM1gMgENFYYeg1JWrCFrA==", + "dev": true, + "license": "MIT" + }, "node_modules/@electron-toolkit/eslint-config-prettier": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@electron-toolkit/eslint-config-prettier/-/eslint-config-prettier-3.0.1.tgz", @@ -1890,99 +1908,48 @@ "node": ">=18.0.0" } }, - "node_modules/@jest/diff-sequences": { - "version": "30.5.0", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.5.0.tgz", - "integrity": "sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@jest/expect-utils": { - "version": "30.5.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.2.tgz", - "integrity": "sha512-d/HOLSrJUlBIl6n3LzOa7cjW3xdePm5H5gQw2lixZ/0h157l9sw3mLblzFqnPcTbhDzhRQdBOX3A3KcG73nm5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/get-type": "30.5.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/get-type": { - "version": "30.5.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.5.0.tgz", - "integrity": "sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/pattern": { - "version": "30.5.0", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.5.0.tgz", - "integrity": "sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*", - "jest-regex-util": "30.5.0" + "jest-get-type": "^29.6.3" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/react-is-18": { - "name": "react-is", - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jest/react-is-19": { - "name": "react-is", - "version": "19.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.1.tgz", - "integrity": "sha512-RRieF6IyxQBkcK6pP8xOHprLTPW6QjRkbGdImtqNme+/hYVwCZkLQLdlZGOhUqXwkS9IEynaGvPJtv6XB/cz0Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@jest/schemas": { - "version": "30.5.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", - "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "license": "MIT", "dependencies": { - "@sinclair/typebox": "^0.34.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/types": { - "version": "30.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", - "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/pattern": "30.5.0", - "@jest/schemas": "30.5.0", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^17.0.33", - "chalk": "^4.1.2" + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jimp/bmp": { @@ -2558,6 +2525,70 @@ "node": "^22.20 || ^24.12 || >=25" } }, + "node_modules/@nethesis/chat-island": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.2.tgz", + "integrity": "sha512-LESp0zs79EWsjM3W7oidf8hPwEIcquL5gVLxYbtAoefe1Cw/skt/ZdkS+nrWoFF3mJRPmY7PadHIFvVdnuSaeg==", + "dev": true, + "license": "AGPL-3.0-or-later", + "dependencies": { + "@xmpp/client": "^0.14.0", + "use-sync-external-store": "^1.2.0", + "zustand": "^4.5.7" + }, + "peerDependencies": { + "react": "^18.2.0 || ^19.0.0", + "react-dom": "^18.2.0 || ^19.0.0" + } + }, + "node_modules/@nethesis/nethesis-brands-svg-icons": { + "version": "6.2.1", + "resolved": "git+ssh://git@github.com/nethesis/Font-Awesome.git#dbcf431acf0e504145486c9ac70f14946279e2e7", + "dev": true, + "hasInstallScript": true, + "license": "UNLICENSED", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.2.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@nethesis/nethesis-brands-svg-icons/node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", + "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@nethesis/nethesis-light-svg-icons": { + "version": "6.2.1", + "resolved": "git+ssh://git@github.com/nethesis/Font-Awesome.git#3e110fb0ae63495fb8b7ca9811e5f07eed1ac962", + "dev": true, + "hasInstallScript": true, + "license": "UNLICENSED", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.2.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@nethesis/nethesis-light-svg-icons/node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", + "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/@nethesis/nethesis-solid-svg-icons": { "version": "6.2.1", "resolved": "git+ssh://git@github.com/nethesis/Font-Awesome.git#1a6b58a7581627785d4a4cbc0314ed3d185a1288", @@ -3562,9 +3593,9 @@ ] }, "node_modules/@sinclair/typebox": { - "version": "0.34.52", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", - "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true, "license": "MIT" }, @@ -3863,14 +3894,14 @@ } }, "node_modules/@types/jest": { - "version": "30.0.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", - "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", "dev": true, "license": "MIT", "dependencies": { - "expect": "^30.0.0", - "pretty-format": "^30.0.0" + "expect": "^29.0.0", + "pretty-format": "^29.0.0" } }, "node_modules/@types/jest/node_modules/ansi-styles": { @@ -3887,19 +3918,18 @@ } }, "node_modules/@types/jest/node_modules/pretty-format": { - "version": "30.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", - "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/react-is-18": "npm:react-is@^18.3.1", - "@jest/react-is-19": "npm:react-is@^19.2.5", - "@jest/schemas": "30.5.0", - "ansi-styles": "^5.2.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@types/json-schema": { @@ -4031,9 +4061,9 @@ "optional": true }, "node_modules/@types/yargs": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", - "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, "license": "MIT", "dependencies": { @@ -4434,15 +4464,410 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", - "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz", + "integrity": "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==", "devOptional": true, "license": "MIT", "engines": { "node": ">=10.0.0" } }, + "node_modules/@xmpp/base64": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/base64/-/base64-0.14.0.tgz", + "integrity": "sha512-tz2LuzLMtjGSVVeuXDnDw19H+uOrqhrRFcQKJ3THV0HVjerDewT8WKXdrtBVSQ7n4Ue0k+awYcIE7qDD9rwMMQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/client": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/client/-/client-0.14.0.tgz", + "integrity": "sha512-Y6k77iifYOGuWncOLRr6dVmbsQvcsIFjYI9pXhkSzQDDNnd3hVJGgo/Xx+W/0/o1+kg/tPm/NwX5Yq77NTd9xA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/client-core": "^0.14.0", + "@xmpp/iq": "^0.14.0", + "@xmpp/middleware": "^0.14.0", + "@xmpp/reconnect": "^0.14.0", + "@xmpp/resolve": "^0.14.0", + "@xmpp/resource-binding": "^0.14.0", + "@xmpp/sasl": "^0.14.0", + "@xmpp/sasl-anonymous": "^0.14.0", + "@xmpp/sasl-ht-sha-256-none": "^0.14.0", + "@xmpp/sasl-plain": "^0.14.0", + "@xmpp/sasl-scram-sha-1": "^0.14.0", + "@xmpp/sasl2": "^0.14.0", + "@xmpp/starttls": "^0.14.0", + "@xmpp/stream-features": "^0.14.0", + "@xmpp/stream-management": "^0.14.0", + "@xmpp/tcp": "^0.14.0", + "@xmpp/tls": "^0.14.0", + "@xmpp/websocket": "^0.14.0", + "saslmechanisms": "^0.1.1" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/client-core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/client-core/-/client-core-0.14.0.tgz", + "integrity": "sha512-fW0C6vn4y8Jp1g8uBmCETuOmEDXpjFc/mfY8P0J88nhK2AdPOB5m0ntz0yyAXcPd16smnHVckiOsk9qBjF9dDA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/connection": "^0.14.0", + "@xmpp/events": "^0.14.0", + "@xmpp/jid": "^0.14.0", + "@xmpp/sasl": "^0.14.0", + "@xmpp/xml": "^0.14.0", + "saslmechanisms": "^0.1.1" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/connection": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/connection/-/connection-0.14.0.tgz", + "integrity": "sha512-VRnukXwiXWCsRVQVISUiAxHHgRWH37nxdUaz50o0+cUAYyqtlHIJ2zy+ZHMlxkEWtl+XciNLxwkJKbypJFQheQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/error": "^0.14.0", + "@xmpp/events": "^0.14.0", + "@xmpp/jid": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/connection-tcp": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/connection-tcp/-/connection-tcp-0.14.0.tgz", + "integrity": "sha512-gvYyUghuCHW0qalEYaZvbHeTnEoXc+hCCWP/qvoVGjjSQNwkYRUsy1/8RP/sA6RlQ2sR0nhpkJkJE6K/4rsFIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/connection": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/error": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/error/-/error-0.14.0.tgz", + "integrity": "sha512-b4W/MwAZl8basfmYhcemK3De92xBOiSrIz0VY2cnN2ss1VMsa4d32GuaJGBIpa4ulN/2DFb3vPCeTn5jXvHAJw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/events": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/events/-/events-0.14.0.tgz", + "integrity": "sha512-6mKRIEi69sYr8H9SrkJKaXobOgCq/sU6/pKTQS5cuQZCy0qLuyx9uttkOyAYmtUbVD+HSrXYS72KhMpdQQh88Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "events": "^3.3.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/id": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/id/-/id-0.14.0.tgz", + "integrity": "sha512-0n8OFYPWkBYDi5fHGiJT6SLg9ncOflTmINzjHzt5A3NxEMVrYmqxbRB44u3NLMk1gBNqGtEkc2wl0WHjS0tHWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/iq": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/iq/-/iq-0.14.0.tgz", + "integrity": "sha512-0r3QVKR4XAvkZ4shQwPBkSM21sSfj26Cg8+AYBkd0BKJTde7mRQCISBNidt1xiXA5VPH1+6Qx7fmtPzk3uel+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/events": "^0.14.0", + "@xmpp/id": "^0.14.0", + "@xmpp/middleware": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/jid": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/jid/-/jid-0.14.0.tgz", + "integrity": "sha512-ggiNgjblkeHPbHJ7JLOMIqxc1qQQt0gV+LhXI16afib2wLr120YgvRChY04gjkvQ+IF2sGz7mzPvcAukTmNGHA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/middleware": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/middleware/-/middleware-0.14.0.tgz", + "integrity": "sha512-UGm7ed5NEMapE/z0jqY5daGSBqto/iciDjtyncoXHZdOnR4iFYFF9gSO/65Z1HsL2pbHQpcK0WS+Kn+FGOxPTw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/error": "^0.14.0", + "@xmpp/jid": "^0.14.0", + "@xmpp/xml": "^0.14.0", + "koa-compose": "^4.1.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/reconnect": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/reconnect/-/reconnect-0.14.0.tgz", + "integrity": "sha512-XaaT3KrFLf1ZfYZCIx11zauT8bIVXRz9FMaGj4mofq1tC8SiKvIIqJXSgrouhkibb9vPeM9XSiGkH47B/1hc6g==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/events": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/resolve": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/resolve/-/resolve-0.14.0.tgz", + "integrity": "sha512-S4Rhupb2zS4EtT4EFUJLPl2pPSFPfrjp/1bxPil+zBt9sNcbrvIwSNaYeQAAfLD/yYb8/DhaxC/blvdHyM1Xzw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/events": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/resource-binding": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/resource-binding/-/resource-binding-0.14.0.tgz", + "integrity": "sha512-b8EyHUOpkAS25b6cpOQ8fv7cCLfOpJq4dkgs6Td0MdODMmcfWEh38siZKaP0OoNmYWZCxBSANdsBmeidozJxqA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/sasl": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/sasl/-/sasl-0.14.0.tgz", + "integrity": "sha512-C6mWvtRhJCCjv0Q6uuc3FUuDdgUhnX7lCF9afmNT5umy1XB0l1iRmBJYTriSHNBwgErM3i3mydafeRjpuQfP5Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/base64": "^0.14.0", + "@xmpp/error": "^0.14.0", + "@xmpp/events": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/sasl-anonymous": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/sasl-anonymous/-/sasl-anonymous-0.14.0.tgz", + "integrity": "sha512-lZ8jaYuKBpfQ2T5Bv+7yxII9OduV1a+mlNkKtG94WchrVzR8fU6VpbTrez88KajA42ngcVCtiO3i6tPepYyK8Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "sasl-anonymous": "^0.1.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/sasl-ht-sha-256-none": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/sasl-ht-sha-256-none/-/sasl-ht-sha-256-none-0.14.0.tgz", + "integrity": "sha512-LmMSzX35bI/V2lV26k/hYPm8Pn7InsBEX72b86+ugIBQpzD8/jmB1F/Mfm5vrbWkMLl2KWe61gE+L/p0mvLZdA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/sasl-plain": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/sasl-plain/-/sasl-plain-0.14.0.tgz", + "integrity": "sha512-TGQX6gsCi6LP2lPNkkd+HoZ1ynCesRMQrtJrWbDAa6oMyCwie9xuBcG/5lDJ5fn03G7xxRh1YSQp+x8yFK+q4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "sasl-plain": "^0.1.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/sasl-scram-sha-1": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/sasl-scram-sha-1/-/sasl-scram-sha-1-0.14.0.tgz", + "integrity": "sha512-0ZrsMDx9Haou2yTCzDCwvMsYPvHCxF2bkpyBuiPoYAOWRsIQH1TssZK3d88N7wSvvojter905DNwLPizdaF3og==", + "dev": true, + "license": "ISC", + "dependencies": { + "sasl-scram-sha-1": "^1.3.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/sasl2": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/sasl2/-/sasl2-0.14.0.tgz", + "integrity": "sha512-OcDIDr9xwiOO58yqr6hj0eh9CfKOvwBbNDNhC0wByA07cwOsoojLb1dv3WR7pKk1cETv6wHWQ1o/leRoDB/Yzg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/base64": "^0.14.0", + "@xmpp/error": "^0.14.0", + "@xmpp/events": "^0.14.0", + "@xmpp/jid": "^0.14.0", + "@xmpp/sasl": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@xmpp/starttls": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/starttls/-/starttls-0.14.0.tgz", + "integrity": "sha512-n21Oy5pyD6Cipo96SAVI1ASx/5qo/z3W7J1TWZSG3/gGgrTaCB+VSV0xI+FqRexVJysg3lw3cBidYQL+Lp/pHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/events": "^0.14.0", + "@xmpp/tls": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/stream-features": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/stream-features/-/stream-features-0.14.0.tgz", + "integrity": "sha512-XoogP53qv1lzq/TNnzydT0KmmDKsJ7vpbV1c33fcuBDY0LCmPWA2U5th+Atn3JjEMlyznpVDFco9BF1NgFTHzg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/stream-management": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/stream-management/-/stream-management-0.14.0.tgz", + "integrity": "sha512-i7qLB8KXzLtm2TZXgtVlBprI4Vm8lykJ7Gth2TFavBTky+PQFNr2BH4lGxxvZ7/WkYbhx2jsmDT9JjI7sUCRdw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/error": "^0.14.0", + "@xmpp/events": "^0.14.0", + "@xmpp/time": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/tcp": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/tcp/-/tcp-0.14.0.tgz", + "integrity": "sha512-vJb5Y60ub+YClK01l+653+qpIe6vedw/82szuB4IU50eTDTL8voer6eGK7AMJOJzoZzRofbLh8Ow5txAyZ8vXw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/connection-tcp": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/time": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/time/-/time-0.14.0.tgz", + "integrity": "sha512-KlOLwZXXYrRiIZ+Lg0Rg+iDxIBLfCgVQOkIaYG2nieLVtbrHItI5gv2eI2I6m0cPsX8LajGkCpvQTqUCNZclag==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/tls": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/tls/-/tls-0.14.0.tgz", + "integrity": "sha512-nY/nHlHYgs3i2+xwt/5Ff3J4aCdZADdTOH+NwdfgqBIK9kWDJPW43nnIrbrZgmUL3YOjW5sb1lUI20bFUJACww==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/connection": "^0.14.0", + "@xmpp/connection-tcp": "^0.14.0", + "@xmpp/events": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/websocket": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/websocket/-/websocket-0.14.0.tgz", + "integrity": "sha512-mRjpRHtOujrPIT7I/X2xvn8w6X/7J8gGPfGIKNGLJHBQu1OlT5noUd++mslCAcGdCOf5TGwtJvE7a8CPtSnTFg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/connection": "^0.14.0", + "@xmpp/events": "^0.14.0", + "@xmpp/xml": "^0.14.0" + }, + "engines": { + "node": ">= 20.10" + } + }, + "node_modules/@xmpp/xml": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@xmpp/xml/-/xml-0.14.0.tgz", + "integrity": "sha512-1rrj3SaIM51wtJUn1l2n4FK2e1QLfEmma9bsD1utaaosA8elpCyWi12QDPfaYoTyWSXNvQ7mGzvFevUJUs1mcQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@xmpp/events": "^0.14.0", + "ltx": "^3.1.2" + }, + "engines": { + "node": ">= 20.10" + } + }, "node_modules/abbrev": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", @@ -4854,6 +5279,12 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/applescript": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/applescript/-/applescript-1.0.0.tgz", + "integrity": "sha512-yvtNHdWvtbYEiIazXAdp/NY+BBb65/DAseqlNiJQjOx9DynuzOYDbVLBJvuc0ve0VL9x6B3OHF6eH52y9hCBtQ==", + "dev": true + }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -5034,6 +5465,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, "node_modules/asn1js": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", @@ -5113,6 +5563,23 @@ "node": ">= 4.0.0" } }, + "node_modules/auto-launch": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/auto-launch/-/auto-launch-5.0.6.tgz", + "integrity": "sha512-OgxiAm4q9EBf9EeXdPBiVNENaWE3jUZofwrhAkWjHDYGezu1k3FRZHU8V2FBxGuSJOHzKmTJEd0G7L7/0xDGFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "applescript": "^1.0.0", + "mkdirp": "^0.5.1", + "path-is-absolute": "^1.0.0", + "untildify": "^3.0.2", + "winreg": "1.2.4" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/autoprefixer": { "version": "10.6.1", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.6.1.tgz", @@ -5278,6 +5745,13 @@ "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==", "license": "MIT" }, + "node_modules/bn.js": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "dev": true, + "license": "MIT" + }, "node_modules/boolean": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", @@ -5295,9 +5769,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", - "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, "license": "MIT", "dependencies": { @@ -5317,6 +5791,89 @@ "node": ">=8" } }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "dev": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/browserslist": { "version": "4.29.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", @@ -5392,6 +5949,13 @@ "dev": true, "license": "MIT" }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true, + "license": "MIT" + }, "node_modules/builder-util": { "version": "26.16.0", "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.16.0.tgz", @@ -5726,9 +6290,9 @@ "license": "MIT" }, "node_modules/ci-info": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", - "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, "funding": [ { @@ -5741,6 +6305,20 @@ "node": ">=8" } }, + "node_modules/cipher-base": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", + "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", @@ -6019,6 +6597,53 @@ "buffer": "^5.1.0" } }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "node_modules/cross-dirname": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", @@ -6028,6 +6653,16 @@ "optional": true, "peer": true }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -6043,6 +6678,33 @@ "node": ">= 8" } }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", @@ -6300,6 +6962,17 @@ "node": ">=6" } }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -6315,6 +6988,35 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, "node_modules/dir-compare": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", @@ -6607,9 +7309,9 @@ } }, "node_modules/electron-builder-notarize/node_modules/js-yaml": { - "version": "3.15.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", - "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -6640,6 +7342,22 @@ "electron-winstaller": "5.4.0" } }, + "node_modules/electron-builder/node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/electron-builder/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -6809,6 +7527,29 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -6826,37 +7567,19 @@ } }, "node_modules/engine.io-client": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.7.tgz", - "integrity": "sha512-GyAvmPA7gnRCpDQbYACAy79Lg4ewevrmaPzySZz0OVvgyZc3gEfLLqPTYk8wVBScjOEpM9ZO4KryyFpVItjGEA==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.2.tgz", + "integrity": "sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw==", "dev": true, "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1", + "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.21.0", + "ws": "~8.17.1", "xmlhttprequest-ssl": "~2.1.1" } }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/engine.io-parser": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", @@ -7490,27 +8213,37 @@ "node": ">=0.8.x" } }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "node_modules/exif-parser": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" }, "node_modules/expect": { - "version": "30.5.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.2.tgz", - "integrity": "sha512-0LNuMvs8/5mRYhnCR4k+lGV7fqPMs6Bnksda4S3zsCUmdxBpAn4zU4NNzXdq1pMKe/H4W5t/zVIDSJ/H3e0vDA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.5.2", - "@jest/get-type": "30.5.0", - "jest-matcher-utils": "30.5.2", - "jest-message-util": "30.5.1", - "jest-mock": "30.5.2", - "jest-util": "30.5.1" + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/exponential-backoff": { @@ -8108,9 +8841,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", - "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", "dev": true, "license": "MIT", "dependencies": { @@ -8314,6 +9047,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "node_modules/hasown": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", @@ -8327,6 +9085,18 @@ "node": ">= 0.4" } }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -8388,9 +9158,9 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", - "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true, "license": "BSD-2-Clause" }, @@ -8498,6 +9268,16 @@ "dev": true, "license": "MIT" }, + "node_modules/i18next-http-backend": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.7.3.tgz", + "integrity": "sha512-FgZxrXdRA5u44xfYsJlEBL4/KH3f2IluBpgV/7riW0YW2VEyM8FzVt2XHAOi6id0Ppj7vZvCZVpp5LrGXnc8Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, "node_modules/iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -9193,19 +9973,19 @@ } }, "node_modules/jest-diff": { - "version": "30.5.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.2.tgz", - "integrity": "sha512-rBtHnI6BWTiWj3lM7fOLVfChx7R9B0u9VV3PRHawKs79x6ZjW1QoSrKenaigNGWlvhtoi2BqvDbABDie+Os3xQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/diff-sequences": "30.5.0", - "@jest/get-type": "30.5.0", - "chalk": "^4.1.2", - "pretty-format": "30.5.1" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-diff/node_modules/ansi-styles": { @@ -9221,36 +10001,45 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-diff/node_modules/pretty-format": { - "version": "30.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", - "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/react-is-18": "npm:react-is@^18.3.1", - "@jest/react-is-19": "npm:react-is@^19.2.5", - "@jest/schemas": "30.5.0", - "ansi-styles": "^5.2.0" - }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "30.5.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.2.tgz", - "integrity": "sha512-lFkB365PTIHOhPzwrb9T6gvlDnPpOZ7/c3ewOKKB7bzztqjVrtlyRL2MkyfJXpyY2u2SKw001JKrTx14fBUFcQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/get-type": "30.5.0", - "chalk": "^4.1.2", - "jest-diff": "30.5.2", - "pretty-format": "30.5.1" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils/node_modules/ansi-styles": { @@ -9267,41 +10056,39 @@ } }, "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "30.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", - "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/react-is-18": "npm:react-is@^18.3.1", - "@jest/react-is-19": "npm:react-is@^19.2.5", - "@jest/schemas": "30.5.0", - "ansi-styles": "^5.2.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-message-util": { - "version": "30.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.1.tgz", - "integrity": "sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@jest/types": "30.5.1", - "@types/stack-utils": "^2.0.3", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "jest-util": "30.5.1", - "picomatch": "^4.0.3", - "pretty-format": "30.5.1", + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", "slash": "^3.0.0", - "stack-utils": "^2.0.6" + "stack-utils": "^2.0.3" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-message-util/node_modules/ansi-styles": { @@ -9317,90 +10104,37 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-message-util/node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "30.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", - "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/react-is-18": "npm:react-is@^18.3.1", - "@jest/react-is-19": "npm:react-is@^19.2.5", - "@jest/schemas": "30.5.0", - "ansi-styles": "^5.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/jest-mock": { - "version": "30.5.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.2.tgz", - "integrity": "sha512-KTHb37Fhj8xY8qPFvTFaFJHcdsumQp+ExsUlgoX232Agmc706gagBs53+CYvulV7MVQo9AgXOUxsqzzVBoJlrA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.5.2", - "@jest/types": "30.5.1", - "@types/node": "*", - "jest-util": "30.5.1" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/jest-regex-util": { - "version": "30.5.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.5.0.tgz", - "integrity": "sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-util": { - "version": "30.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", - "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.5.1", + "@jest/types": "^29.6.3", "@types/node": "*", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "graceful-fs": "^4.2.11", - "picomatch": "^4.0.3" + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/jest-util/node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jimp": { @@ -9572,6 +10306,13 @@ "json-buffer": "3.0.1" } }, + "node_modules/koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==", + "dev": true, + "license": "MIT" + }, "node_modules/koffi": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/koffi/-/koffi-2.16.3.tgz", @@ -9717,6 +10458,16 @@ "yallist": "^3.0.2" } }, + "node_modules/ltx": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/ltx/-/ltx-3.1.2.tgz", + "integrity": "sha512-tFSKojN92FqNK6eRTmKK/ROUTUYVWKAxgohz523TPhF1G3nR3DXQS/I7/705rEPrDSloKDgMdRlh0qgMFQoVYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.4.0" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -9762,6 +10513,18 @@ "node": ">= 0.4" } }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -9795,6 +10558,27 @@ "node": ">=8.6" } }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -9870,14 +10654,28 @@ "mini-svg-data-uri": "cli.js" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, "node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^2.0.1" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -9925,7 +10723,6 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -9943,6 +10740,33 @@ "node": "*" } }, + "node_modules/motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/motion/-/motion-11.18.2.tgz", + "integrity": "sha512-JLjvFDuFr42NFtcVoMAyC2sEjnpA8xpy6qWPyzQvCloznAyQ8FIXioxWfHiLtgYhoVpfUqSWpn1h9++skj9+Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "framer-motion": "^11.18.2", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/motion-dom": { "version": "11.18.1", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", @@ -10498,6 +11322,23 @@ "node": ">=6" } }, + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse-bmfont-ascii": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", @@ -10613,6 +11454,24 @@ "dev": true, "license": "ISC" }, + "node_modules/pbkdf2": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/pe-library": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", @@ -10947,9 +11806,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", "dependencies": { @@ -11165,6 +12024,28 @@ "node": ">=10" } }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -11246,6 +12127,27 @@ "dev": true, "license": "MIT" }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -11856,6 +12758,36 @@ "rimraf": "bin.js" } }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -12044,6 +12976,40 @@ "truncate-utf8-bytes": "^1.0.0" } }, + "node_modules/sasl-anonymous": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/sasl-anonymous/-/sasl-anonymous-0.1.0.tgz", + "integrity": "sha512-x+0sdsV0Gie2EexxAUsx6ZoB+X6OCthlNBvAQncQxreEWQJByAPntj0EAgTlJc2kZicoc+yFzeR6cl8VfsQGfA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/sasl-plain": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/sasl-plain/-/sasl-plain-0.1.0.tgz", + "integrity": "sha512-X8mCSfR8y0NryTu0tuVyr4IS2jBunBgyG+3a0gEEkd0nlHGiyqJhlc4EIkzmSwaa7F8S4yo+LS6Cu5qxRkJrmg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/sasl-scram-sha-1": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sasl-scram-sha-1/-/sasl-scram-sha-1-1.4.0.tgz", + "integrity": "sha512-kdP8uAFkak8flnmKTldWnQ98IuC15ASdKxNHWwbqexRj7szHs7y+JEtigLkPoq9gnp/SAxxU4O2huL8OLqSr9w==", + "dev": true, + "license": "MIT" + }, + "node_modules/saslmechanisms": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/saslmechanisms/-/saslmechanisms-0.1.1.tgz", + "integrity": "sha512-pVlvK5ysevz8MzybRnDIa2YMxn0OJ7b9lDiWhMoaKPoJ7YkAg/7YtNjUgaYzElkwHxsw8dBMhaEn7UP6zxEwPg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/sax": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", @@ -12171,6 +13137,27 @@ "node": ">= 0.4" } }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -12848,6 +13835,22 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/sumchecker": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", @@ -12921,6 +13924,19 @@ "url": "https://github.com/sponsors/dcastil" } }, + "node_modules/tailwind-scrollbar": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tailwind-scrollbar/-/tailwind-scrollbar-3.1.0.tgz", + "integrity": "sha512-pmrtDIZeHyu2idTejfV59SbaJyvp1VRjYxAjZBH0jnyrPRo6HL1kD5Glz8VPagasqr6oAx6M05+Tuw429Z8jxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "tailwindcss": "3.x" + } + }, "node_modules/tailwindcss": { "version": "3.4.19", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", @@ -13213,6 +14229,28 @@ "tmp": "^0.2.0" } }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -13484,6 +14522,16 @@ "node": ">= 4.0.0" } }, + "node_modules/untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/unzipper": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.5.tgz", @@ -13703,6 +14751,19 @@ } } }, + "node_modules/vite-plugin-copy": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/vite-plugin-copy/-/vite-plugin-copy-0.1.6.tgz", + "integrity": "sha512-bqIaefZOE2Jx8P5wJuHKL5GzCERa/pcwdUQWaocyTNXgalN2xkxXH7LmqRJ34V2OlKF2F9E/zj0zITS7U6PpUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.7" + }, + "engines": { + "node": ">=14.8.0" + } + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -13909,6 +14970,13 @@ "node": ">=4" } }, + "node_modules/winreg": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz", + "integrity": "sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -13963,9 +15031,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", - "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "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": { diff --git a/package.json b/package.json index cc85c4e0..54e20a39 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", + "@nethesis/chat-island": "^0.1.2", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json index d8b17718..7aaaffd1 100644 --- a/public/locales/en/translations.json +++ b/public/locales/en/translations.json @@ -699,6 +699,12 @@ "Z-A label": "Z-A", "EXT label": "Extension" }, + "Chat": { + "Chat": "Chat", + "New chat": "New chat", + "No conversations": "No conversations", + "You": "You" + }, "LastCalls": { "Last calls": "Last calls", "No calls": "No calls", diff --git a/public/locales/it/translations.json b/public/locales/it/translations.json index 7e5bf0d9..43fea398 100644 --- a/public/locales/it/translations.json +++ b/public/locales/it/translations.json @@ -699,6 +699,12 @@ "Z-A label": "Z-A", "EXT label": "Interno" }, + "Chat": { + "Chat": "Chat", + "New chat": "Nuova chat", + "No conversations": "Nessuna conversazione", + "You": "Tu" + }, "LastCalls": { "Last calls": "Ultime chiamate", "No calls": "Nessuna chiamata", diff --git a/src/main/classes/controllers/AppController.ts b/src/main/classes/controllers/AppController.ts index 83756f98..76f11a21 100644 --- a/src/main/classes/controllers/AppController.ts +++ b/src/main/classes/controllers/AppController.ts @@ -1,6 +1,7 @@ import { LoginController } from './LoginController' import { NethLinkController } from './NethLinkController' import { PhoneIslandController } from './PhoneIslandController' +import { ChatIslandController } from './ChatIslandController' import { TrayController } from './TrayController' import { Log } from '@shared/utils/logger' import { DevToolsController } from './DevToolsController' @@ -32,6 +33,11 @@ export class AppController { Log.warning('unable to correctly close the PhoneIslandController:', e) } } + try { + await ChatIslandController.instance?.safeQuit() + } catch (e) { + Log.warning('unable to correctly close the ChatIslandController:', e) + } if (NethLinkController.instance) { try { await NethLinkController.instance.safeQuit() diff --git a/src/main/classes/controllers/ChatIslandController.ts b/src/main/classes/controllers/ChatIslandController.ts new file mode 100644 index 00000000..3ee75529 --- /dev/null +++ b/src/main/classes/controllers/ChatIslandController.ts @@ -0,0 +1,54 @@ +import { ChatIslandWindow } from '../windows' +import { Log } from '@shared/utils/logger' +import { screen } from 'electron' + +export class ChatIslandController { + static instance: ChatIslandController | undefined + window: ChatIslandWindow + private wantFocus = false + + constructor() { + ChatIslandController.instance = this + this.window = new ChatIslandWindow() + } + + // Sized to the island, in the bottom-right corner; hidden when there is nothing to show. + resize(size: { w: number; h: number }) { + try { + const window = this.window.getWindow() + if (!window) return + if (size.w < 8 || size.h < 8) { + window.hide() + return + } + const { x, y, width, height } = screen.getPrimaryDisplay().workArea + const w = Math.min(Math.ceil(size.w), width) + const h = Math.min(Math.ceil(size.h), height) + window.setBounds({ + x: x + width - w, + y: y + height - h, + width: w, + height: h, + }) + if (this.wantFocus) { + this.wantFocus = false + window.show() + window.focus() + } else if (!window.isVisible()) window.showInactive() + } catch (e) { + Log.warning('error during resizing ChatIslandWindow:', e) + } + } + + // Focus once the island has sized the window for what it opens. + focus() { + const window = this.window.getWindow() + if (window?.isVisible()) window.focus() + this.wantFocus = true + } + + async safeQuit() { + ChatIslandController.instance = undefined + await this.window.quit(true) + } +} diff --git a/src/main/classes/controllers/index.ts b/src/main/classes/controllers/index.ts index fc8760ba..10e6d278 100644 --- a/src/main/classes/controllers/index.ts +++ b/src/main/classes/controllers/index.ts @@ -4,3 +4,4 @@ export * from './PhoneIslandController' export * from './TrayController' export * from './DevToolsController' export * from './CommandBarController' +export * from './ChatIslandController' diff --git a/src/main/classes/windows/ChatIslandWindow.ts b/src/main/classes/windows/ChatIslandWindow.ts new file mode 100644 index 00000000..ae8d6ca4 --- /dev/null +++ b/src/main/classes/windows/ChatIslandWindow.ts @@ -0,0 +1,42 @@ +import { PAGES } from '@shared/types' +import { BaseWindow } from './BaseWindow' + +// Transparent, always on top: the chat stays in view with NethLink closed. +export class ChatIslandWindow extends BaseWindow { + constructor() { + super(PAGES.CHATISLAND, { + width: 440, + height: 600, + show: false, + focusable: true, + acceptFirstMouse: true, + fullscreenable: false, + autoHideMenuBar: true, + closable: false, + alwaysOnTop: true, + minimizable: false, + maximizable: false, + movable: false, + resizable: false, + skipTaskbar: true, + roundedCorners: false, + parent: undefined, + transparent: true, + hiddenInMissionControl: true, + hasShadow: false, + fullscreen: false, + enableLargerThanScreen: false, + frame: false, + thickFrame: false, + trafficLightPosition: { x: 0, y: 0 }, + webPreferences: { + nodeIntegration: true, + backgroundThrottling: false, + }, + }) + + this.addOnBuildListener(() => { + this.getWindow()?.setAlwaysOnTop(true, 'screen-saver') + }) + } +} diff --git a/src/main/classes/windows/index.ts b/src/main/classes/windows/index.ts index 7cc92b28..2c435f92 100644 --- a/src/main/classes/windows/index.ts +++ b/src/main/classes/windows/index.ts @@ -4,3 +4,4 @@ export * from './NethLinkWindow' export * from './PhoneIslandWindow' export * from './DevToolsWindow' export * from './CommandBarWindow' +export * from './ChatIslandWindow' diff --git a/src/main/lib/ipcEvents.ts b/src/main/lib/ipcEvents.ts index ac720809..ac1c5033 100644 --- a/src/main/lib/ipcEvents.ts +++ b/src/main/lib/ipcEvents.ts @@ -2,6 +2,7 @@ import { AccountController } from '@/classes/controllers' import { LoginController } from '@/classes/controllers/LoginController' import { PhoneIslandController } from '@/classes/controllers/PhoneIslandController' import { CommandBarController } from '@/classes/controllers/CommandBarController' +import { ChatIslandController } from '@/classes/controllers/ChatIslandController' import { IPC_EVENTS } from '@shared/constants' import { Account, OnDraggingWindow, PAGES } from '@shared/types' import { @@ -345,6 +346,36 @@ export function registerIpcEvents() { clipboard.writeText(text) }) + // Chat island window: size, and island events between it and NethLink. + ipcMain.on(IPC_EVENTS.CHAT_ISLAND_RESIZE, (_, size) => { + ChatIslandController.instance?.resize(size) + }) + ipcMain.on(IPC_EVENTS.CHAT_TO_ISLAND, (_, name, detail) => { + try { + ChatIslandController.instance?.window.emit( + IPC_EVENTS.CHAT_TO_ISLAND, + name, + detail, + ) + if (name === 'chat-island-open' || name === 'chat-island-new') { + ChatIslandController.instance?.focus() + } + } catch (e) { + Log.warning('chat island unreachable:', e) + } + }) + ipcMain.on(IPC_EVENTS.CHAT_FROM_ISLAND, (_, name, detail) => { + try { + NethLinkController.instance?.window.emit( + IPC_EVENTS.CHAT_FROM_ISLAND, + name, + detail, + ) + } catch (e) { + Log.warning('nethlink unreachable:', e) + } + }) + ipcMain.on(IPC_EVENTS.PHONE_ISLAND_RESIZE, (_, size) => { PhoneIslandController.instance.resize(size) }) diff --git a/src/main/main.ts b/src/main/main.ts index 602595ec..91e20b39 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -21,6 +21,7 @@ import { import { AccountController } from './classes/controllers' import { PhoneIslandController } from './classes/controllers/PhoneIslandController' import { CommandBarController } from './classes/controllers/CommandBarController' +import { ChatIslandController } from './classes/controllers/ChatIslandController' import { Account, AuthAppData, @@ -131,6 +132,7 @@ function startup() { } await PhoneIslandController.instance.logout() + await ChatIslandController.instance?.safeQuit() NethLinkController.instance.logout() AccountController.instance.logout() await delay(1000) @@ -754,6 +756,16 @@ async function attachProtocolListeners() { } break } + case 'chat': { + // The chat opens in its own window, not in NethLink. + ipcMain.emit( + IPC_EVENTS.CHAT_TO_ISLAND, + undefined, + to ? 'chat-island-open' : 'chat-island-new', + to ? { username: to } : undefined, + ) + return new Promise((resolve) => resolve) + } default: Log.warning('Unknown nethlink action:', action) } @@ -954,6 +966,7 @@ async function createNethLink(show: boolean = true) { if (show) NethLinkController.instance.show() await delay(1000) new PhoneIslandController() + new ChatIslandController() checkForUpdate() const account = store.get('account') as Account if (account) { diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 5140e346..81d1018d 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -14,6 +14,7 @@ import { AvailableThemes, PAGES } from '@shared/types' import { delay } from '@shared/utils/utils' import i18next from 'i18next' import { DevToolsPage } from './pages/DevToolsPage' +import { ChatIslandPage } from './pages/ChatIslandPage' import { parseThemeToClassName } from './utils' import { useRegisterStoreHook, useSharedState } from '@renderer/store' import { PageContext, usePageCtx } from './contexts/pageContext' @@ -143,6 +144,10 @@ const RequestStateComponent = () => { path: PAGES.COMMANDBAR, element: , }, + { + path: PAGES.CHATISLAND, + element: , + }, ], }, ]) @@ -162,6 +167,9 @@ const Layout = ({ theme, page }: { theme?: AvailableThemes; page?: PAGES }) => { if (page === PAGES.PHONEISLAND) { await import('@nethesis/phone-island/dist/index.css') } + if (page === PAGES.CHATISLAND) { + await import('@nethesis/chat-island/dist/index.css') + } setIsCSSLoaded(true) } diff --git a/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx b/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx index 9756fde3..e18aa38c 100644 --- a/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx +++ b/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx @@ -5,6 +5,7 @@ import { faInfoCircle as InfoMenuIcon, faStar as FavouriteMenuIcon, faSquareParking as ParkedCallMenuIcon, + faComments as ChatMenuIcon, } from '@fortawesome/free-solid-svg-icons' import { useNethlinkData, useSharedState } from '@renderer/store' import { ParkingType } from '@shared/types' @@ -27,6 +28,8 @@ export function Sidebar({ onChangeMenu }: SidebarProps): JSX.Element { ) const [, setPhonebookSearchModule] = useNethlinkData('phonebookSearchModule') const [missedCalls] = useNethlinkData('missedCalls') + const [chatStatus] = useNethlinkData('chatStatus') + const [chatUnread] = useNethlinkData('chatUnread') const [notifications] = useSharedState('notifications') const [lastMenu, setLastMenu] = useState( MENU_ELEMENT.FAVOURITES, @@ -113,6 +116,16 @@ export function Sidebar({ onChangeMenu }: SidebarProps): JSX.Element { isSelected={selectedSidebarMenu === MENU_ELEMENT.PARKED_CALLS} /> )} + {/* CHAT: shown once the chat window is connecting */} + {chatStatus && ( + 0} + onClick={() => handleSidebarMenuSelection(MENU_ELEMENT.CHAT)} + isSelected={selectedSidebarMenu === MENU_ELEMENT.CHAT} + /> + )} {/* APP UPDATE */} { + const d = new Date(ts) + return d.toDateString() === new Date().toDateString() + ? d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) + : d.toLocaleDateString() +} + +export function ChatModule() { + const [conversations] = useNethlinkData('chatConversations') + + return ( + <> + openChat()} + actionIcon={NewChatIcon} + actionText={t('Chat.New chat')} + /> + + {conversations?.length ? ( + conversations.map((c) => ( +
openChat(c.peer)} + className='flex items-center gap-3 px-5 py-2 cursor-pointer dark:hover:bg-hoverDark hover:bg-hoverLight' + > + +
+
+ + {c.name} + + {c.last && ( + + {time(c.last.ts)} + + )} +
+
+ + {c.last && + (c.last.mine + ? `${t('Chat.You')}: ` + : c.kind === 'group' && c.last.nick + ? `${c.last.nick}: ` + : '')} + {c.last?.body} + + {c.unread > 0 && ( + + {c.unread} + + )} +
+
+
+ )) + ) : ( + + )} +
+ + ) +} diff --git a/src/renderer/src/components/Modules/NethlinkModules.tsx b/src/renderer/src/components/Modules/NethlinkModules.tsx index 7e17cce6..c6a03929 100644 --- a/src/renderer/src/components/Modules/NethlinkModules.tsx +++ b/src/renderer/src/components/Modules/NethlinkModules.tsx @@ -6,6 +6,7 @@ import { AboutModule } from './NethVoice/About/AboutModule' import classNames from 'classnames' import { FavouritesModule } from './NethVoice/Speeddials/Favourites/FavouritesModule' import { ParkingModule } from './NethVoice/Parking/ParkingModule' +import { ChatModule } from './NethVoice/Chat/ChatModule' import { PhoneBookSearchModule } from './NethVoice/SearchResults/PhoneBookSearchModule' import { usePhonebookSearchModule } from './NethVoice/SearchResults/hook/usePhoneBookSearchModule' @@ -42,6 +43,8 @@ export const NethLinkModules = () => { return case MENU_ELEMENT.ABOUT: return + case MENU_ELEMENT.CHAT: + return default: ;<>modules } diff --git a/src/renderer/src/hooks/useChatBridge.ts b/src/renderer/src/hooks/useChatBridge.ts new file mode 100644 index 00000000..fa17c053 --- /dev/null +++ b/src/renderer/src/hooks/useChatBridge.ts @@ -0,0 +1,50 @@ +import { useEffect } from 'react' +import { useNethlinkData } from '@renderer/store' +import { IPC_EVENTS } from '@shared/constants' + +/** Opens a conversation, or the new chat panel, in the chat window. */ +export const openChat = (username?: string) => + window.electron.send( + IPC_EVENTS.CHAT_TO_ISLAND, + username ? 'chat-island-open' : 'chat-island-new', + username ? { username } : undefined, + ) + +/** Island state for NethLink, and the colleagues for the island. */ +export function useChatBridge(username?: string) { + const [chatStatus, setChatStatus] = useNethlinkData('chatStatus') + const [, setChatUnread] = useNethlinkData('chatUnread') + const [, setChatConversations] = useNethlinkData('chatConversations') + const [operators] = useNethlinkData('operators') + const up = !!chatStatus + + useEffect(() => { + window.electron.receive(IPC_EVENTS.CHAT_FROM_ISLAND, (name, detail) => { + if (name === 'chat-island-status') setChatStatus(detail?.status) + if (name === 'chat-island-unread') setChatUnread(detail?.total ?? 0) + if (name === 'chat-island-conversations') + setChatConversations(detail?.conversations ?? []) + }) + return () => window.electron.removeAllListeners(IPC_EVENTS.CHAT_FROM_ISLAND) + }, []) + + // Names, avatars, presence and number; sent again once the island is up. + useEffect(() => { + const ops: any = operators?.operators || {} + const avatars: any = operators?.avatars || {} + const contacts = Object.values(ops) + .filter((op: any) => op?.username && op.username !== username) + .map((op: any) => ({ + username: op.username, + name: op.name || op.username, + avatar: avatars[op.username], + presence: op.mainPresence, + number: op.endpoints?.mainextension?.[0]?.id, + })) + if (contacts.length && up) { + window.electron.send(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-island-contacts', { + contacts, + }) + } + }, [operators, username, up]) +} diff --git a/src/renderer/src/pages/ChatIslandPage.tsx b/src/renderer/src/pages/ChatIslandPage.tsx new file mode 100644 index 00000000..b6709cf9 --- /dev/null +++ b/src/renderer/src/pages/ChatIslandPage.tsx @@ -0,0 +1,125 @@ +import { ChatIsland } from '@nethesis/chat-island' +import { useSharedState } from '@renderer/store' +import { IPC_EVENTS } from '@shared/constants' +import { Log } from '@shared/utils/logger' +import { useEffect, useMemo, useState } from 'react' + +// Room around the island for its shadows. +const PAD = 24 +// Island events NethLink listens to. +const OUT = [ + 'chat-island-status', + 'chat-island-unread', + 'chat-island-conversations', +] + +export function ChatIslandPage() { + const [account] = useSharedState('account') + const [theme] = useSharedState('theme') + const [enabled, setEnabled] = useState(false) + + const allowed = + !!account?.data?.profile?.macro_permissions?.nethvoice_cti?.permissions + ?.chat?.value + + // The chat is on for this NethVoice when its gateway answers. + useEffect(() => { + setEnabled(false) + if (!account?.host || !allowed) return + fetch(`https://${account.host}/chat-gw/healthz`) + .then((r) => setEnabled(r.ok)) + .catch(() => setEnabled(false)) + }, [account?.host, allowed]) + + const dataConfig = useMemo( + () => + account?.jwtToken + ? btoa(`${account.host}:${account.username}:${account.jwtToken}`) + : '', + [account?.host, account?.username, account?.jwtToken], + ) + const on = enabled && !!dataConfig + + // The window follows the island's size. + useEffect(() => { + if (!on) { + window.electron.send(IPC_EVENTS.CHAT_ISLAND_RESIZE, { w: 0, h: 0 }) + return + } + let observer: ResizeObserver | undefined + const timer = setInterval(() => { + const root = document.querySelector('.chat-island-root') + if (!root || observer) return + observer = new ResizeObserver(() => { + const { width, height } = root.getBoundingClientRect() + window.electron.send( + IPC_EVENTS.CHAT_ISLAND_RESIZE, + width < 8 + ? { w: 0, h: 0 } + : { w: width + 16 + PAD, h: height + 20 + PAD }, + ) + }) + observer.observe(root) + }, 200) + return () => { + clearInterval(timer) + observer?.disconnect() + } + }, [on]) + + // Events between the island and NethLink. + useEffect(() => { + if (!on) return + window.electron.receive(IPC_EVENTS.CHAT_TO_ISLAND, (name, detail) => + window.dispatchEvent(new CustomEvent(name, { detail })), + ) + const forward = (e: Event) => + window.electron.send( + IPC_EVENTS.CHAT_FROM_ISLAND, + e.type, + (e as CustomEvent).detail, + ) + const call = (e: Event) => { + const number = (e as CustomEvent).detail?.number + number && window.electron.send(IPC_EVENTS.EMIT_START_CALL, number) + } + const notify = (e: Event) => { + const { peer, name, body } = (e as CustomEvent).detail || {} + if (!body) return + const n = new Notification(name || peer, { body }) + n.onclick = () => + window.electron.send(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-island-open', { + username: peer, + }) + } + const error = (e: Event) => + Log.warning('chat island', (e as CustomEvent).detail) + OUT.forEach((n) => window.addEventListener(n, forward)) + window.addEventListener('chat-island-call', call) + window.addEventListener('chat-island-notify', notify) + window.addEventListener('chat-island-error', error) + return () => { + window.electron.removeAllListeners(IPC_EVENTS.CHAT_TO_ISLAND) + OUT.forEach((n) => window.removeEventListener(n, forward)) + window.removeEventListener('chat-island-call', call) + window.removeEventListener('chat-island-notify', notify) + window.removeEventListener('chat-island-error', error) + } + }, [on]) + + if (!on) return null + return ( + <> + {/* Fixed widths: the island must not shrink to the window it sizes. */} + + + + ) +} diff --git a/src/renderer/src/pages/NethLinkPage.tsx b/src/renderer/src/pages/NethLinkPage.tsx index a9b4d040..8b84f3cb 100644 --- a/src/renderer/src/pages/NethLinkPage.tsx +++ b/src/renderer/src/pages/NethLinkPage.tsx @@ -13,6 +13,7 @@ import { debouncer } from '@shared/utils/utils' import { useAccount } from '@renderer/hooks/useAccount' import { Sidebar } from '@renderer/components/Modules/NethVoice/BaseModule/Sidebar' import { sendNotification } from '@renderer/utils' +import { useChatBridge } from '@renderer/hooks/useChatBridge' export interface NethLinkPageProps { handleRefreshConnection: () => void @@ -38,6 +39,7 @@ export function NethLinkPage({ handleRefreshConnection }: NethLinkPageProps) { const { NethVoiceAPI } = useLoggedNethVoiceAPI() const accountMeInterval = useRef() + useChatBridge(account?.username) useInitialize(() => { Log.info('INITIALIZE NETHLINK FRONTEND') diff --git a/src/renderer/src/store.ts b/src/renderer/src/store.ts index 807622ca..a078e2ce 100644 --- a/src/renderer/src/store.ts +++ b/src/renderer/src/store.ts @@ -178,6 +178,9 @@ export const useNethlinkData = createGlobalStateHook({ }, showAddContactModule: false, showPhonebookSearchModule: false, + chatStatus: undefined, + chatUnread: 0, + chatConversations: [], } as NethLinkPageData).useGlobalState export const useLoginPageData = createGlobalStateHook({ diff --git a/src/shared/constants.ts b/src/shared/constants.ts index d864c871..af0bb29a 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -38,6 +38,7 @@ export enum MENU_ELEMENT { LAST_CALLS, PARKED_CALLS, ABOUT, + CHAT, } export enum IPC_EVENTS { LOGIN = 'LOGIN', @@ -45,6 +46,9 @@ export enum IPC_EVENTS { START_CALL = 'START_CALL', EMIT_START_CALL = 'EMIT_START_CALL', PHONE_ISLAND_RESIZE = 'PHONE_ISLAND_RESIZE', + CHAT_ISLAND_RESIZE = 'CHAT_ISLAND_RESIZE', + CHAT_TO_ISLAND = 'CHAT_TO_ISLAND', + CHAT_FROM_ISLAND = 'CHAT_FROM_ISLAND', LOGIN_WINDOW_RESIZE = 'LOGIN_WINDOW_RESIZE', CHANGE_THEME = 'CHANGE_THEME', OPEN_DEV_TOOLS = 'OPEN_DEV_TOOLS', diff --git a/src/shared/types.ts b/src/shared/types.ts index 50298a61..2f3f6d5a 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -21,6 +21,7 @@ export enum PAGES { NETHLINK = 'NethLink', DEVTOOLS = 'devtoolspage', COMMANDBAR = 'commandbarpage', + CHATISLAND = 'chatislandpage', } export type StateType = [T | undefined, (value: T | undefined) => void] @@ -503,6 +504,20 @@ export type NethLinkPageData = { speeddialsModule?: SpeedDialModuleData phonebookSearchModule?: PhonebookSearchModuleData phonebookModule?: PhonebookModuleData + chatStatus?: string + chatUnread?: number + chatConversations?: ChatConversation[] +} + +// One row of the chat-island-conversations event. +export type ChatConversation = { + peer: string + kind: 'chat' | 'group' + name: string + avatar?: string + online: boolean + unread: number + last?: { body: string; ts: number; mine: boolean; nick?: string } } export type SpeedDialModuleData = { From f718402746a9d464c3bc4c5d86add641e421be96 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 30 Sep 2026 16:27:54 +0200 Subject: [PATCH 02/50] chat: drag the chat window from the dock and the header --- package-lock.json | 8 ++--- package.json | 2 +- .../controllers/ChatIslandController.ts | 29 ++++++++++++--- src/main/lib/ipcEvents.ts | 3 ++ src/renderer/src/pages/ChatIslandPage.tsx | 35 ++++++++++++++++++- 5 files changed, 67 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 10f91db3..9fd7afee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.2", + "@nethesis/chat-island": "^0.1.3", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.2.tgz", - "integrity": "sha512-LESp0zs79EWsjM3W7oidf8hPwEIcquL5gVLxYbtAoefe1Cw/skt/ZdkS+nrWoFF3mJRPmY7PadHIFvVdnuSaeg==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.3.tgz", + "integrity": "sha512-FqVJplSp3VhtM6q6iHk/mOMUldPD+C26BkSPFSLxMU+Vrc/nGCHjSUI8yANvLpnfn+yjzs+kAFjB3fHY3JLSBA==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 54e20a39..070ab137 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.2", + "@nethesis/chat-island": "^0.1.3", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/main/classes/controllers/ChatIslandController.ts b/src/main/classes/controllers/ChatIslandController.ts index 3ee75529..74b9ee8e 100644 --- a/src/main/classes/controllers/ChatIslandController.ts +++ b/src/main/classes/controllers/ChatIslandController.ts @@ -6,13 +6,15 @@ export class ChatIslandController { static instance: ChatIslandController | undefined window: ChatIslandWindow private wantFocus = false + // Distance from the work area's bottom-right corner, kept after a drag. + private anchor = { right: 0, bottom: 0 } constructor() { ChatIslandController.instance = this this.window = new ChatIslandWindow() } - // Sized to the island, in the bottom-right corner; hidden when there is nothing to show. + // Sized to the island, grown from its bottom-right corner; hidden when there is nothing to show. resize(size: { w: number; h: number }) { try { const window = this.window.getWindow() @@ -21,12 +23,12 @@ export class ChatIslandController { window.hide() return } - const { x, y, width, height } = screen.getPrimaryDisplay().workArea + const { x, y, width, height } = this.workArea() const w = Math.min(Math.ceil(size.w), width) const h = Math.min(Math.ceil(size.h), height) window.setBounds({ - x: x + width - w, - y: y + height - h, + x: Math.max(x, x + width - this.anchor.right - w), + y: Math.max(y, y + height - this.anchor.bottom - h), width: w, height: h, }) @@ -40,6 +42,25 @@ export class ChatIslandController { } } + private workArea() { + const window = this.window.getWindow() + return window?.isVisible() + ? screen.getDisplayMatching(window.getBounds()).workArea + : screen.getPrimaryDisplay().workArea + } + + // After a drag: the new corner is where the island grows from. + keepPosition() { + const window = this.window.getWindow() + if (!window) return + const b = window.getBounds() + const { x, y, width, height } = this.workArea() + this.anchor = { + right: Math.max(0, x + width - b.x - b.width), + bottom: Math.max(0, y + height - b.y - b.height), + } + } + // Focus once the island has sized the window for what it opens. focus() { const window = this.window.getWindow() diff --git a/src/main/lib/ipcEvents.ts b/src/main/lib/ipcEvents.ts index ac1c5033..aef9f5c5 100644 --- a/src/main/lib/ipcEvents.ts +++ b/src/main/lib/ipcEvents.ts @@ -237,6 +237,9 @@ export function registerIpcEvents() { const cursorPosition = screen.getCursorScreenPoint() const deltaX = cursorPosition.x - draggingWindow.startMousePosition.x const deltaY = cursorPosition.y - draggingWindow.startMousePosition.y + if (window.title === PAGES.CHATISLAND) { + ChatIslandController.instance?.keepPosition() + } if (window.title === PAGES.PHONEISLAND) { const bounds = window.getBounds() Log.info( diff --git a/src/renderer/src/pages/ChatIslandPage.tsx b/src/renderer/src/pages/ChatIslandPage.tsx index b6709cf9..77d39cc6 100644 --- a/src/renderer/src/pages/ChatIslandPage.tsx +++ b/src/renderer/src/pages/ChatIslandPage.tsx @@ -2,7 +2,7 @@ import { ChatIsland } from '@nethesis/chat-island' import { useSharedState } from '@renderer/store' import { IPC_EVENTS } from '@shared/constants' import { Log } from '@shared/utils/logger' -import { useEffect, useMemo, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' // Room around the island for its shadows. const PAD = 24 @@ -107,6 +107,38 @@ export function ChatIslandPage() { } }, [on]) + // The dock and the window header move the whole window; a drag is not a click. + const moved = useRef(false) + const onDragStart = (e: React.PointerEvent) => { + if (e.button !== 0) return + const from = { x: e.screenX, y: e.screenY } + moved.current = false + window.electron.send(IPC_EVENTS.START_DRAG) + const move = (ev: PointerEvent) => { + if (Math.abs(ev.screenX - from.x) + Math.abs(ev.screenY - from.y) > 4) + moved.current = true + } + const stop = () => { + window.electron.send(IPC_EVENTS.STOP_DRAG) + window.removeEventListener('pointermove', move) + window.removeEventListener('pointerup', stop) + window.removeEventListener('blur', stop) + } + window.addEventListener('pointermove', move) + window.addEventListener('pointerup', stop) + window.addEventListener('blur', stop) + } + useEffect(() => { + const click = (e: MouseEvent) => { + if (!moved.current) return + moved.current = false + e.stopPropagation() + e.preventDefault() + } + document.addEventListener('click', click, true) + return () => document.removeEventListener('click', click, true) + }, []) + if (!on) return null return ( <> @@ -116,6 +148,7 @@ export function ChatIslandPage() { dataConfig={dataConfig} theme={theme} drag={false} + onDragStart={onDragStart} newChatButton={false} maxHeads={5} notifications='auto' From 65e0dd7eb21867020b4e99fa94f8eff9e3746c16 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 30 Sep 2026 16:39:31 +0200 Subject: [PATCH 03/50] chat: keep the chat window on screen while dragging; island 0.1.4 --- package-lock.json | 8 ++++---- package.json | 2 +- src/main/lib/ipcEvents.ts | 13 +++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9fd7afee..866be134 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.3", + "@nethesis/chat-island": "^0.1.4", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.3.tgz", - "integrity": "sha512-FqVJplSp3VhtM6q6iHk/mOMUldPD+C26BkSPFSLxMU+Vrc/nGCHjSUI8yANvLpnfn+yjzs+kAFjB3fHY3JLSBA==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.4.tgz", + "integrity": "sha512-Mra7P1MBAcJD3Uoh/1zaZDOC7AVj7NSYgMfzgd/+JIyWleD+1IxXE2tBrMfPkxmhYEag7bC8MLmy0Xu3gtloYw==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 070ab137..a5c33b9e 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.3", + "@nethesis/chat-island": "^0.1.4", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/main/lib/ipcEvents.ts b/src/main/lib/ipcEvents.ts index aef9f5c5..4414d8f3 100644 --- a/src/main/lib/ipcEvents.ts +++ b/src/main/lib/ipcEvents.ts @@ -279,6 +279,19 @@ export function registerIpcEvents() { }, false, ) + } else if (window.title === PAGES.CHATISLAND) { + // Kept inside the screen under the cursor, like the phone island. + const { width, height } = window.getBounds() + const wa = screen.getDisplayNearestPoint(cursorPosition).workArea + window.setBounds( + { + x: Math.min(Math.max(newX, wa.x), wa.x + wa.width - width), + y: Math.min(Math.max(newY, wa.y), wa.y + wa.height - height), + width, + height, + }, + false, + ) } else { const [w, h] = window.getContentSize() window.setBounds( From bf819cbb9fd85a6c643c139edc9821807edf044b Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 30 Sep 2026 16:58:59 +0200 Subject: [PATCH 04/50] chat: retry the chat check, resend its state when NethLink reloads --- src/renderer/src/hooks/useChatBridge.ts | 2 ++ src/renderer/src/pages/ChatIslandPage.tsx | 28 ++++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/hooks/useChatBridge.ts b/src/renderer/src/hooks/useChatBridge.ts index fa17c053..53c44dca 100644 --- a/src/renderer/src/hooks/useChatBridge.ts +++ b/src/renderer/src/hooks/useChatBridge.ts @@ -25,6 +25,8 @@ export function useChatBridge(username?: string) { if (name === 'chat-island-conversations') setChatConversations(detail?.conversations ?? []) }) + // The chat window may be up already: ask for its state. + window.electron.send(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-sync') return () => window.electron.removeAllListeners(IPC_EVENTS.CHAT_FROM_ISLAND) }, []) diff --git a/src/renderer/src/pages/ChatIslandPage.tsx b/src/renderer/src/pages/ChatIslandPage.tsx index 77d39cc6..8552fecd 100644 --- a/src/renderer/src/pages/ChatIslandPage.tsx +++ b/src/renderer/src/pages/ChatIslandPage.tsx @@ -22,13 +22,17 @@ export function ChatIslandPage() { !!account?.data?.profile?.macro_permissions?.nethvoice_cti?.permissions ?.chat?.value - // The chat is on for this NethVoice when its gateway answers. + // The chat is on for this NethVoice when its gateway answers; asked again every minute until it does. useEffect(() => { setEnabled(false) if (!account?.host || !allowed) return - fetch(`https://${account.host}/chat-gw/healthz`) - .then((r) => setEnabled(r.ok)) - .catch(() => setEnabled(false)) + let timer: ReturnType | undefined + const probe = () => + fetch(`https://${account.host}/chat-gw/healthz`) + .then((r) => (r.ok ? setEnabled(true) : Promise.reject())) + .catch(() => (timer = setTimeout(probe, 60 * 1000))) + probe() + return () => clearTimeout(timer) }, [account?.host, allowed]) const dataConfig = useMemo( @@ -70,15 +74,23 @@ export function ChatIslandPage() { // Events between the island and NethLink. useEffect(() => { if (!on) return - window.electron.receive(IPC_EVENTS.CHAT_TO_ISLAND, (name, detail) => - window.dispatchEvent(new CustomEvent(name, { detail })), - ) - const forward = (e: Event) => + // Last value of each event, sent again when NethLink (re)loads. + const last: Record = {} + window.electron.receive(IPC_EVENTS.CHAT_TO_ISLAND, (name, detail) => { + if (name !== 'chat-sync') + return window.dispatchEvent(new CustomEvent(name, { detail })) + Object.entries(last).forEach(([n, d]) => + window.electron.send(IPC_EVENTS.CHAT_FROM_ISLAND, n, d), + ) + }) + const forward = (e: Event) => { + last[e.type] = (e as CustomEvent).detail window.electron.send( IPC_EVENTS.CHAT_FROM_ISLAND, e.type, (e as CustomEvent).detail, ) + } const call = (e: Event) => { const number = (e as CustomEvent).detail?.number number && window.electron.send(IPC_EVENTS.EMIT_START_CALL, number) From a46ffec13c927aa710fc3c04861013924350adad Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 30 Sep 2026 17:15:39 +0200 Subject: [PATCH 05/50] command bar: chat with a colleague Chat button and a chat icon on colleague rows while the chat is online; Ctrl/Cmd+Enter chats, Enter still calls. --- public/locales/en/translations.json | 4 +- public/locales/it/translations.json | 4 +- src/main/lib/ipcEvents.ts | 12 ++++ src/renderer/src/pages/CommandBarPage.tsx | 67 ++++++++++++++++++++++- 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json index 7aaaffd1..5b8f8738 100644 --- a/public/locales/en/translations.json +++ b/public/locales/en/translations.json @@ -998,7 +998,9 @@ }, "CommandBar": { "Placeholder": "Search contact or dial number...", - "Call": "Call" + "Call": "Call", + "Chat": "Chat", + "Chat hint": "Chat (Ctrl/⌘+Enter)" }, "Errors": { "browser_permissions": "Browser permissions error", diff --git a/public/locales/it/translations.json b/public/locales/it/translations.json index 43fea398..79d81778 100644 --- a/public/locales/it/translations.json +++ b/public/locales/it/translations.json @@ -998,7 +998,9 @@ }, "CommandBar": { "Placeholder": "Cerca contatto o componi numero...", - "Call": "Chiama" + "Call": "Chiama", + "Chat": "Chat", + "Chat hint": "Chat (Ctrl/⌘+Invio)" }, "Errors": { "browser_permissions": "Errore nei permessi del browser", diff --git a/src/main/lib/ipcEvents.ts b/src/main/lib/ipcEvents.ts index 4414d8f3..d6e2b336 100644 --- a/src/main/lib/ipcEvents.ts +++ b/src/main/lib/ipcEvents.ts @@ -390,6 +390,18 @@ export function registerIpcEvents() { } catch (e) { Log.warning('nethlink unreachable:', e) } + // The command bar only needs to know whether the chat is there. + if (name === 'chat-island-status') { + try { + CommandBarController.instance?.window.emit( + IPC_EVENTS.CHAT_FROM_ISLAND, + name, + detail, + ) + } catch (e) { + Log.warning('command bar unreachable:', e) + } + } }) ipcMain.on(IPC_EVENTS.PHONE_ISLAND_RESIZE, (_, size) => { diff --git a/src/renderer/src/pages/CommandBarPage.tsx b/src/renderer/src/pages/CommandBarPage.tsx index 8c6c1029..46bc2185 100644 --- a/src/renderer/src/pages/CommandBarPage.tsx +++ b/src/renderer/src/pages/CommandBarPage.tsx @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faPhone, + faComment, faSearch, faXmark, faUser, @@ -90,6 +91,9 @@ export function CommandBarPage() { const avatarsRef = useRef(null) const lastFetchRef = useRef(0) // Timestamp of last successful operators/avatars fetch const [operatorVersion, setOperatorVersion] = useState(0) // Bumped when operators data changes, triggers useMemo + // Chat window status: colleagues can be chatted with while it is online. + const [chatStatus, setChatStatus] = useState() + const canChat = chatStatus === 'online' const isPhoneNumber = searchText.trim().length > 0 && getIsPhoneNumber(searchText.trim()) @@ -228,6 +232,14 @@ export function CommandBarPage() { [NethVoiceAPI], ) + useEffect(() => { + window.electron.receive(IPC_EVENTS.CHAT_FROM_ISLAND, (name, detail) => { + if (name === 'chat-island-status') setChatStatus(detail?.status) + }) + window.electron.send(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-sync') + return () => window.electron.removeAllListeners(IPC_EVENTS.CHAT_FROM_ISLAND) + }, []) + useEffect(() => { window.electron.receive(IPC_EVENTS.SHOW_COMMAND_BAR, () => { setSearchText('') @@ -302,6 +314,22 @@ export function CommandBarPage() { [searchText], ) + const handleChat = useCallback((username?: string) => { + if (!username) return + window.electron.send(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-island-open', { + username, + }) + window.electron.send(IPC_EVENTS.HIDE_COMMAND_BAR) + }, []) + + // The selected colleague, when there is one to chat with. + const chatTarget = + canChat && selectedIndex >= 0 + ? allItems[selectedIndex]?.contact?.isOperator + ? allItems[selectedIndex]?.username + : undefined + : undefined + const handleCallSelected = useCallback(() => { if (selectedIndex >= 0 && selectedIndex < allItems.length) { const item = allItems[selectedIndex] @@ -344,7 +372,9 @@ export function CommandBarPage() { if (e.key === 'Enter') { e.preventDefault() - handleCallSelected() + // Ctrl/Cmd+Enter chats with the selected colleague, Enter calls. + if ((e.ctrlKey || e.metaKey) && chatTarget) handleChat(chatTarget) + else handleCallSelected() return } } @@ -440,6 +470,24 @@ export function CommandBarPage() { {t('CommandBar.Call')} + + {canChat && ( + + )} {/* Dropdown results */} @@ -522,7 +570,7 @@ export function CommandBarPage() { className='h-4 w-4 text-gray-500 dark:text-gray-400' /> )} -
+
{contact.displayName} @@ -535,6 +583,21 @@ export function CommandBarPage() { )}
+ {isOperator && canChat && item.username && ( + + )}
) })} From 2efbbb29c40cb66a25df96a9261d4e1931779238 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 30 Sep 2026 17:17:07 +0200 Subject: [PATCH 06/50] chat: richer desktop notification; island 0.1.5 --- package-lock.json | 8 ++++---- package.json | 2 +- src/renderer/src/pages/ChatIslandPage.tsx | 7 +++++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 866be134..b51d8fdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.4", + "@nethesis/chat-island": "^0.1.5", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.4.tgz", - "integrity": "sha512-Mra7P1MBAcJD3Uoh/1zaZDOC7AVj7NSYgMfzgd/+JIyWleD+1IxXE2tBrMfPkxmhYEag7bC8MLmy0Xu3gtloYw==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.5.tgz", + "integrity": "sha512-Z6ZBMhPuZU78ukEnth4C5E/apzbVo0QPzl7/h6IkW3FBuEfmthsBZ/GnismUOJ+s4aaUC63T0j7mgmjywxVsRg==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index a5c33b9e..28492a2e 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.4", + "@nethesis/chat-island": "^0.1.5", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/renderer/src/pages/ChatIslandPage.tsx b/src/renderer/src/pages/ChatIslandPage.tsx index 8552fecd..a085e17f 100644 --- a/src/renderer/src/pages/ChatIslandPage.tsx +++ b/src/renderer/src/pages/ChatIslandPage.tsx @@ -96,9 +96,12 @@ export function ChatIslandPage() { number && window.electron.send(IPC_EVENTS.EMIT_START_CALL, number) } const notify = (e: Event) => { - const { peer, name, body } = (e as CustomEvent).detail || {} + const { peer, name, body, kind, author, text, avatar } = + (e as CustomEvent).detail || {} if (!body) return - const n = new Notification(name || peer, { body }) + // Groups: "Author · Group"; the avatar as icon. + const title = kind === 'group' ? `${author} · ${name}` : name || peer + const n = new Notification(title, { body: text || body, icon: avatar }) n.onclick = () => window.electron.send(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-island-open', { username: peer, From 2e1ba8b270780e89b144acb0f4082294dab752ad Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 30 Sep 2026 17:25:26 +0200 Subject: [PATCH 07/50] search: chat with a colleague from the results --- .../NethVoice/SearchResults/SearchNumber.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx b/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx index 6f5dab7f..460d8747 100644 --- a/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx +++ b/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx @@ -7,6 +7,9 @@ import { usePhonebookSearchModule } from './hook/usePhoneBookSearchModule' import { ContactNameAndActions } from '@renderer/components/Modules/NethVoice/BaseModule/ContactNameAndAction' import { useFavouriteModule } from '../Speeddials/hook/useFavouriteModule' import { ClassNames } from '@renderer/utils' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faComment } from '@fortawesome/free-solid-svg-icons' +import { openChat } from '@renderer/hooks/useChatBridge' export interface SearchNumberProps { user: SearchData @@ -18,6 +21,7 @@ export function SearchNumber({ user, className, onClick }: SearchNumberProps) { const phoneBookModule = usePhonebookSearchModule() const [searchText] = phoneBookModule.searchTextState const [operators] = useNethlinkData('operators') + const [chatStatus] = useNethlinkData('chatStatus') const { isSearchAlsoAFavourite } = useFavouriteModule() const getUsernameFromPhoneNumber = (number: string) => { @@ -126,6 +130,17 @@ export function SearchNumber({ user, className, onClick }: SearchNumberProps) { } /> + {/* A colleague: chat with them */} + {username && chatStatus === 'online' && ( + + )} {onClick && ( - - {canChat && ( - - )} {/* Dropdown results */} From 1eb498c3f663213f83fc4dce886e4203eb360131 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 1 Oct 2026 08:47:35 +0200 Subject: [PATCH 09/50] chat: delete or leave from the list, translations, group names; island 0.1.6 Chat strings go in src/renderer/public/locales too (the copy the windows read). --- package-lock.json | 8 +- package.json | 2 +- public/locales/en/translations.json | 7 +- public/locales/it/translations.json | 7 +- .../public/locales/en/translations.json | 14 +- .../public/locales/it/translations.json | 14 +- .../Modules/NethVoice/Chat/ChatModule.tsx | 128 ++++++++++++++++-- src/shared/types.ts | 1 + 8 files changed, 163 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index b51d8fdb..92344f3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.5", + "@nethesis/chat-island": "^0.1.6", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.5.tgz", - "integrity": "sha512-Z6ZBMhPuZU78ukEnth4C5E/apzbVo0QPzl7/h6IkW3FBuEfmthsBZ/GnismUOJ+s4aaUC63T0j7mgmjywxVsRg==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.6.tgz", + "integrity": "sha512-fpckIIhc5TTtMeMVycp7z5ozg0H9Eip69QkP2tFz2YCLrgj5F+kF7IFXDhOz1nx8UKV/Kg9H4xyEchu7euKnmA==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 28492a2e..6975151e 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.5", + "@nethesis/chat-island": "^0.1.6", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json index 21079880..e9f139a9 100644 --- a/public/locales/en/translations.json +++ b/public/locales/en/translations.json @@ -703,7 +703,12 @@ "Chat": "Chat", "New chat": "New chat", "No conversations": "No conversations", - "You": "You" + "You": "You", + "Delete": "Delete", + "Leave": "Leave", + "Delete confirm": "Delete the conversation with \"{{name}}\"? Your copy of the messages is removed.", + "Delete group confirm": "Delete the group \"{{name}}\" for everyone? Its messages are removed for all members.", + "Leave confirm": "Leave the group \"{{name}}\"? You stop receiving its messages and your copy is removed." }, "LastCalls": { "Last calls": "Last calls", diff --git a/public/locales/it/translations.json b/public/locales/it/translations.json index 36f5fb9b..3e67c279 100644 --- a/public/locales/it/translations.json +++ b/public/locales/it/translations.json @@ -703,7 +703,12 @@ "Chat": "Chat", "New chat": "Nuova chat", "No conversations": "Nessuna conversazione", - "You": "Tu" + "You": "Tu", + "Delete": "Elimina", + "Leave": "Abbandona", + "Delete confirm": "Eliminare la conversazione con \"{{name}}\"? La tua copia dei messaggi viene rimossa.", + "Delete group confirm": "Eliminare il gruppo \"{{name}}\" per tutti? I suoi messaggi vengono rimossi per tutti i membri.", + "Leave confirm": "Abbandonare il gruppo \"{{name}}\"? Non riceverai più i suoi messaggi e la tua copia viene rimossa." }, "LastCalls": { "Last calls": "Ultime chiamate", diff --git a/src/renderer/public/locales/en/translations.json b/src/renderer/public/locales/en/translations.json index 16883fba..9bf6b074 100644 --- a/src/renderer/public/locales/en/translations.json +++ b/src/renderer/public/locales/en/translations.json @@ -698,6 +698,17 @@ "Z-A label": "Z-A", "EXT label": "Extension" }, + "Chat": { + "Chat": "Chat", + "New chat": "New chat", + "No conversations": "No conversations", + "You": "You", + "Delete": "Delete", + "Leave": "Leave", + "Delete confirm": "Delete the conversation with \"{{name}}\"? Your copy of the messages is removed.", + "Delete group confirm": "Delete the group \"{{name}}\" for everyone? Its messages are removed for all members.", + "Leave confirm": "Leave the group \"{{name}}\"? You stop receiving its messages and your copy is removed." + }, "LastCalls": { "Last calls": "Last calls", "No calls": "No calls", @@ -992,7 +1003,8 @@ }, "CommandBar": { "Placeholder": "Search contact or dial number...", - "Call": "Call" + "Call": "Call", + "Chat hint": "Chat (Ctrl/⌘+Enter)" }, "Errors": { "browser_permissions": "Browser permissions error", diff --git a/src/renderer/public/locales/it/translations.json b/src/renderer/public/locales/it/translations.json index 468aa8de..ee2dba8d 100644 --- a/src/renderer/public/locales/it/translations.json +++ b/src/renderer/public/locales/it/translations.json @@ -698,6 +698,17 @@ "Z-A label": "Z-A", "EXT label": "Interno" }, + "Chat": { + "Chat": "Chat", + "New chat": "Nuova chat", + "No conversations": "Nessuna conversazione", + "You": "Tu", + "Delete": "Elimina", + "Leave": "Abbandona", + "Delete confirm": "Eliminare la conversazione con \"{{name}}\"? La tua copia dei messaggi viene rimossa.", + "Delete group confirm": "Eliminare il gruppo \"{{name}}\" per tutti? I suoi messaggi vengono rimossi per tutti i membri.", + "Leave confirm": "Abbandonare il gruppo \"{{name}}\"? Non riceverai più i suoi messaggi e la tua copia viene rimossa." + }, "LastCalls": { "Last calls": "Ultime chiamate", "No calls": "Nessuna chiamata", @@ -992,7 +1003,8 @@ }, "CommandBar": { "Placeholder": "Cerca contatto o componi numero...", - "Call": "Chiama" + "Call": "Chiama", + "Chat hint": "Chat (Ctrl/⌘+Invio)" }, "Errors": { "browser_permissions": "Errore nei permessi del browser", diff --git a/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx b/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx index 5a38caad..2473a534 100644 --- a/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx +++ b/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx @@ -1,9 +1,20 @@ +import { createRef, useState } from 'react' import { faComments as EmptyIcon, faPenToSquare as NewChatIcon, + faRightFromBracket as LeaveIcon, + faTrash as DeleteIcon, + faTriangleExclamation as WarningIcon, + faUsers as GroupIcon, } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { t } from 'i18next' -import { useNethlinkData } from '@renderer/store' +import { useNethlinkData, useSharedState } from '@renderer/store' +import { IPC_EVENTS } from '@shared/constants' +import { ChatConversation } from '@shared/types' +import { Modal } from '@renderer/components' +import { Button } from '@renderer/components/Nethesis' +import { parseThemeToClassName, truncate } from '@renderer/utils' import { ModuleTitle } from '@renderer/components/ModuleTitle' import { Scrollable } from '@renderer/components/Scrollable' import { EmptyList } from '@renderer/components/EmptyList' @@ -17,8 +28,82 @@ const time = (ts: number) => { : d.toLocaleDateString() } +// Leaving a group I do not own; deleting a chat, or a group I own for everyone. +const leaves = (c: ChatConversation) => c.kind === 'group' && !c.owner + +function DeleteDialog({ + conversation, + close, +}: { + conversation: ChatConversation + close: () => void +}) { + const [theme] = useSharedState('theme') + const cancelRef = createRef() + const name = truncate(conversation.name, 30) + const confirm = () => { + window.electron.send(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-island-delete', { + username: conversation.peer, + }) + close() + } + return ( + + +
+
+
+

+ {leaves(conversation) ? t('Chat.Leave') : t('Chat.Delete')} +

+

+ {conversation.kind === 'group' + ? conversation.owner + ? t('Chat.Delete group confirm', { name }) + : t('Chat.Leave confirm', { name }) + : t('Chat.Delete confirm', { name })} +

+
+
+ + + + +
+ ) +} + export function ChatModule() { const [conversations] = useNethlinkData('chatConversations') + const [operators] = useNethlinkData('operators') + const [toDelete, setToDelete] = useState() + const nameOf = (u: string) => operators?.operators?.[u]?.name || u return ( <> @@ -34,14 +119,20 @@ export function ChatModule() {
openChat(c.peer)} - className='flex items-center gap-3 px-5 py-2 cursor-pointer dark:hover:bg-hoverDark hover:bg-hoverLight' + className='group flex items-center gap-3 px-5 py-2 cursor-pointer dark:hover:bg-hoverDark hover:bg-hoverLight' > - + {c.kind === 'group' && !c.avatar ? ( + + + + ) : ( + + )}
@@ -59,7 +150,7 @@ export function ChatModule() { (c.last.mine ? `${t('Chat.You')}: ` : c.kind === 'group' && c.last.nick - ? `${c.last.nick}: ` + ? `${nameOf(c.last.nick)}: ` : '')} {c.last?.body} @@ -70,12 +161,31 @@ export function ChatModule() { )}
+
)) ) : ( )} + {toDelete && ( + setToDelete(undefined)} + /> + )} ) } diff --git a/src/shared/types.ts b/src/shared/types.ts index 2f3f6d5a..b8f747e0 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -516,6 +516,7 @@ export type ChatConversation = { name: string avatar?: string online: boolean + owner?: boolean unread: number last?: { body: string; ts: number; mine: boolean; nick?: string } } From e05567bec5a2b3862ef2775d58c26169d466e1d7 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 1 Oct 2026 09:11:22 +0200 Subject: [PATCH 10/50] chat: Messages list like the last calls, one chat icon, chat after last calls Dividers and spacing of the last calls, short dates, comment-dots everywhere, New chat with comment-medical. Italian months and years in full also in the last calls ("2 mesi fa"). Island 0.1.7. --- package-lock.json | 8 +- package.json | 2 +- public/locales/en/translations.json | 1 + public/locales/it/translations.json | 1 + .../public/locales/en/translations.json | 1 + .../public/locales/it/translations.json | 1 + .../Modules/NethVoice/BaseModule/Sidebar.tsx | 22 +-- .../Modules/NethVoice/Chat/ChatModule.tsx | 169 +++++++++++------- .../NethVoice/SearchResults/SearchNumber.tsx | 4 +- .../src/components/Nethesis/CallsDate.tsx | 4 +- src/renderer/src/pages/CommandBarPage.tsx | 4 +- 11 files changed, 133 insertions(+), 84 deletions(-) diff --git a/package-lock.json b/package-lock.json index 92344f3f..588a43ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.6", + "@nethesis/chat-island": "^0.1.7", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.6.tgz", - "integrity": "sha512-fpckIIhc5TTtMeMVycp7z5ozg0H9Eip69QkP2tFz2YCLrgj5F+kF7IFXDhOz1nx8UKV/Kg9H4xyEchu7euKnmA==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.7.tgz", + "integrity": "sha512-4LeBhaqtDLUAPDTvbX8tQDte0Gb/IR598TWpkWWlgYrKMpj3IGCSie70qoudhRNdlnFUFp7XKj5FvFp9KM6uWg==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 6975151e..acd6cfd8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.6", + "@nethesis/chat-island": "^0.1.7", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json index e9f139a9..ddbefcdf 100644 --- a/public/locales/en/translations.json +++ b/public/locales/en/translations.json @@ -700,6 +700,7 @@ "EXT label": "Extension" }, "Chat": { + "Messages": "Messages", "Chat": "Chat", "New chat": "New chat", "No conversations": "No conversations", diff --git a/public/locales/it/translations.json b/public/locales/it/translations.json index 3e67c279..20670991 100644 --- a/public/locales/it/translations.json +++ b/public/locales/it/translations.json @@ -700,6 +700,7 @@ "EXT label": "Interno" }, "Chat": { + "Messages": "Messaggi", "Chat": "Chat", "New chat": "Nuova chat", "No conversations": "Nessuna conversazione", diff --git a/src/renderer/public/locales/en/translations.json b/src/renderer/public/locales/en/translations.json index 9bf6b074..44545ff5 100644 --- a/src/renderer/public/locales/en/translations.json +++ b/src/renderer/public/locales/en/translations.json @@ -699,6 +699,7 @@ "EXT label": "Extension" }, "Chat": { + "Messages": "Messages", "Chat": "Chat", "New chat": "New chat", "No conversations": "No conversations", diff --git a/src/renderer/public/locales/it/translations.json b/src/renderer/public/locales/it/translations.json index ee2dba8d..2675ed05 100644 --- a/src/renderer/public/locales/it/translations.json +++ b/src/renderer/public/locales/it/translations.json @@ -699,6 +699,7 @@ "EXT label": "Interno" }, "Chat": { + "Messages": "Messaggi", "Chat": "Chat", "New chat": "Nuova chat", "No conversations": "Nessuna conversazione", diff --git a/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx b/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx index e18aa38c..c3a351d0 100644 --- a/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx +++ b/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx @@ -5,7 +5,7 @@ import { faInfoCircle as InfoMenuIcon, faStar as FavouriteMenuIcon, faSquareParking as ParkedCallMenuIcon, - faComments as ChatMenuIcon, + faCommentDots as ChatMenuIcon, } from '@fortawesome/free-solid-svg-icons' import { useNethlinkData, useSharedState } from '@renderer/store' import { ParkingType } from '@shared/types' @@ -102,6 +102,16 @@ export function Sidebar({ onChangeMenu }: SidebarProps): JSX.Element { onClick={() => handleSidebarMenuSelection(MENU_ELEMENT.LAST_CALLS)} isSelected={selectedSidebarMenu === MENU_ELEMENT.LAST_CALLS} /> + {/* CHAT: shown once the chat window is connecting */} + {chatStatus && ( + 0} + onClick={() => handleSidebarMenuSelection(MENU_ELEMENT.CHAT)} + isSelected={selectedSidebarMenu === MENU_ELEMENT.CHAT} + /> + )} {/* PARKED CALLS */} {hasPermission(PERMISSION.PARKINGS) && ( )} - {/* CHAT: shown once the chat window is connecting */} - {chatStatus && ( - 0} - onClick={() => handleSidebarMenuSelection(MENU_ELEMENT.CHAT)} - isSelected={selectedSidebarMenu === MENU_ELEMENT.CHAT} - /> - )} {/* APP UPDATE */} { - const d = new Date(ts) - return d.toDateString() === new Date().toDateString() - ? d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) - : d.toLocaleDateString() +// Like the last calls: "15h ago (30 Sep 2026 18:08)". +// Italian months and years in full: "2 mesi fa", not "2mes fa". +const SHORT: Record Record> = { + en: () => ({ + xSeconds: 's', + xMinutes: 'm', + xHours: 'h', + xDays: 'd', + xMonths: 'mo', + xYears: 'y', + }), + it: (n) => ({ + xSeconds: 's', + xMinutes: 'm', + xHours: 'h', + xDays: 'g', + xMonths: n === 1 ? ' mese' : ' mesi', + xYears: n === 1 ? ' anno' : ' anni', + }), +} +const when = (ts: number) => { + const itLang = i18next.languages?.[0] === 'it' + const short = { + ...(itLang ? it : enGB), + formatDistance: (token: string, count: number) => + `${count}${SHORT[itLang ? 'it' : 'en'](count)[token] || ''}${itLang ? ' fa' : ' ago'}`, + } + return `${formatDistanceToNowStrict(ts, { addSuffix: true, locale: short })} (${format(ts, 'd MMM yyyy HH:mm', { locale: itLang ? it : enGB })})` } // Leaving a group I do not own; deleting a chat, or a group I own for everyone. @@ -108,72 +133,92 @@ export function ChatModule() { return ( <> openChat()} actionIcon={NewChatIcon} actionText={t('Chat.New chat')} /> {conversations?.length ? ( - conversations.map((c) => ( + conversations.map((c, idx) => (
openChat(c.peer)} - className='group flex items-center gap-3 px-5 py-2 cursor-pointer dark:hover:bg-hoverDark hover:bg-hoverLight' + className='group cursor-pointer dark:hover:bg-hoverDark hover:bg-hoverLight hover:shadow-[0px_-1px_0px_0px_#E5E7EB] dark:hover:shadow-[0px_-1px_0px_0px_#374151]' > - {c.kind === 'group' && !c.avatar ? ( - - - - ) : ( - - )} -
-
- - {c.name} - - {c.last && ( - - {time(c.last.ts)} - - )} -
-
- - {c.last && - (c.last.mine - ? `${t('Chat.You')}: ` - : c.kind === 'group' && c.last.nick - ? `${nameOf(c.last.nick)}: ` - : '')} - {c.last?.body} - - {c.unread > 0 && ( - - {c.unread} - - )} +
+
+ {/* Same layout as the last calls */} +
+
+ {c.kind === 'group' && !c.avatar ? ( + + + + ) : ( + + )} +
+
+

+ {c.name} +

+

+ {c.last && + (c.last.mine + ? `${t('Chat.You')}: ` + : c.kind === 'group' && c.last.nick + ? `${nameOf(c.last.nick)}: ` + : '')} + {c.last?.body} +

+ {c.last && ( +

+ {when(c.last.ts)} +

+ )} +
+
+ {c.unread > 0 && ( + + {c.unread} + + )} + +
+
-
)) ) : ( diff --git a/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx b/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx index 460d8747..5b574f93 100644 --- a/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx +++ b/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx @@ -8,7 +8,7 @@ import { ContactNameAndActions } from '@renderer/components/Modules/NethVoice/Ba import { useFavouriteModule } from '../Speeddials/hook/useFavouriteModule' import { ClassNames } from '@renderer/utils' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faComment } from '@fortawesome/free-solid-svg-icons' +import { faCommentDots } from '@fortawesome/free-solid-svg-icons' import { openChat } from '@renderer/hooks/useChatBridge' export interface SearchNumberProps { @@ -137,7 +137,7 @@ export function SearchNumber({ user, className, onClick }: SearchNumberProps) { className='self-center ml-2 shrink-0' onClick={() => openChat(username)} > - + {t('Chat.Chat')} )} diff --git a/src/renderer/src/components/Nethesis/CallsDate.tsx b/src/renderer/src/components/Nethesis/CallsDate.tsx index 18d7ba9e..78e68bc5 100644 --- a/src/renderer/src/components/Nethesis/CallsDate.tsx +++ b/src/renderer/src/components/Nethesis/CallsDate.tsx @@ -74,8 +74,8 @@ export const CallsDate: FC = ({ xMinutes: 'm', xHours: 'h', xDays: 'g', - xMonths: 'mes', - xYears: 'a', + xMonths: count === 1 ? ' mese' : ' mesi', + xYears: count === 1 ? ' anno' : ' anni', } const unit = map[token] || '' diff --git a/src/renderer/src/pages/CommandBarPage.tsx b/src/renderer/src/pages/CommandBarPage.tsx index be65588d..a79ab7a4 100644 --- a/src/renderer/src/pages/CommandBarPage.tsx +++ b/src/renderer/src/pages/CommandBarPage.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faPhone, - faComment, + faCommentDots, faSearch, faXmark, faUser, @@ -575,7 +575,7 @@ export function CommandBarPage() { className='p-2 rounded-lg text-gray-500 hover:text-primary dark:text-gray-400 dark:hover:text-primaryDark dark:hover:bg-bgDark hover:bg-bgLight' > From a28cf6a7c1f0ecdf4177cb4abc4312bf6456ba0f Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 1 Oct 2026 09:54:36 +0200 Subject: [PATCH 11/50] chat: island 0.1.8 (replies) --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 588a43ff..55aa0276 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.7", + "@nethesis/chat-island": "^0.1.8", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.7.tgz", - "integrity": "sha512-4LeBhaqtDLUAPDTvbX8tQDte0Gb/IR598TWpkWWlgYrKMpj3IGCSie70qoudhRNdlnFUFp7XKj5FvFp9KM6uWg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.8.tgz", + "integrity": "sha512-e78saupIs7QbbW5kogRt0wrA4MAAILedqIf8dA7ZZqFWJpR/NvoCKLHyc11MbxccMrbiJL2N2svSnFOVceT0Hw==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index acd6cfd8..876988f0 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.7", + "@nethesis/chat-island": "^0.1.8", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From 10d2f19f0fb5e12c3e5b9263840a6b620f54dccc Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 1 Oct 2026 10:24:31 +0200 Subject: [PATCH 12/50] chat: shared contacts mapping and short dates; island 0.1.9 contactsFromOperators from the island; the short date locale lives in lib/dateTime for the last calls and the messages list. --- package-lock.json | 8 +-- package.json | 2 +- .../Modules/NethVoice/Chat/ChatModule.tsx | 32 ++---------- .../src/components/Nethesis/CallsDate.tsx | 49 +------------------ src/renderer/src/hooks/useChatBridge.ts | 17 +++---- src/renderer/src/lib/dateTime.ts | 42 ++++++++++++++++ 6 files changed, 59 insertions(+), 91 deletions(-) diff --git a/package-lock.json b/package-lock.json index 55aa0276..0af1c376 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.8", + "@nethesis/chat-island": "^0.1.9", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.8.tgz", - "integrity": "sha512-e78saupIs7QbbW5kogRt0wrA4MAAILedqIf8dA7ZZqFWJpR/NvoCKLHyc11MbxccMrbiJL2N2svSnFOVceT0Hw==", + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.9.tgz", + "integrity": "sha512-ERweHcQRZ5J3ehAj1Fs6Df4QEHnvajxWtzGZt0GKKhWfI+Add+zTOa+webRLVITVbjfmvimieSCGDcC8Gp/+oA==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 876988f0..b298a80d 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.8", + "@nethesis/chat-island": "^0.1.9", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx b/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx index 2f984add..d3ce3eda 100644 --- a/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx +++ b/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx @@ -11,46 +11,22 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import i18next, { t } from 'i18next' import { format, formatDistanceToNowStrict } from 'date-fns' import { enGB, it } from 'date-fns/locale' +import { shortLocale } from '@renderer/lib/dateTime' import { useNethlinkData, useSharedState } from '@renderer/store' import { IPC_EVENTS } from '@shared/constants' import { ChatConversation } from '@shared/types' import { Modal } from '@renderer/components' -import { Button } from '@renderer/components/Nethesis' import { parseThemeToClassName, truncate } from '@renderer/utils' import { ModuleTitle } from '@renderer/components/ModuleTitle' import { Scrollable } from '@renderer/components/Scrollable' import { EmptyList } from '@renderer/components/EmptyList' -import { Avatar } from '@renderer/components/Nethesis' +import { Avatar, Button } from '@renderer/components/Nethesis' import { openChat } from '@renderer/hooks/useChatBridge' // Like the last calls: "15h ago (30 Sep 2026 18:08)". -// Italian months and years in full: "2 mesi fa", not "2mes fa". -const SHORT: Record Record> = { - en: () => ({ - xSeconds: 's', - xMinutes: 'm', - xHours: 'h', - xDays: 'd', - xMonths: 'mo', - xYears: 'y', - }), - it: (n) => ({ - xSeconds: 's', - xMinutes: 'm', - xHours: 'h', - xDays: 'g', - xMonths: n === 1 ? ' mese' : ' mesi', - xYears: n === 1 ? ' anno' : ' anni', - }), -} const when = (ts: number) => { - const itLang = i18next.languages?.[0] === 'it' - const short = { - ...(itLang ? it : enGB), - formatDistance: (token: string, count: number) => - `${count}${SHORT[itLang ? 'it' : 'en'](count)[token] || ''}${itLang ? ' fa' : ' ago'}`, - } - return `${formatDistanceToNowStrict(ts, { addSuffix: true, locale: short })} (${format(ts, 'd MMM yyyy HH:mm', { locale: itLang ? it : enGB })})` + const language = i18next.languages?.[0] || 'en' + return `${formatDistanceToNowStrict(ts, { addSuffix: true, locale: shortLocale(language) })} (${format(ts, 'd MMM yyyy HH:mm', { locale: language === 'it' ? it : enGB })})` } // Leaving a group I do not own; deleting a chat, or a group I own for everyone. diff --git a/src/renderer/src/components/Nethesis/CallsDate.tsx b/src/renderer/src/components/Nethesis/CallsDate.tsx index 78e68bc5..e4cac0ff 100644 --- a/src/renderer/src/components/Nethesis/CallsDate.tsx +++ b/src/renderer/src/components/Nethesis/CallsDate.tsx @@ -3,6 +3,7 @@ import { formatDistanceToNowStrict } from 'date-fns' import { format, utcToZonedTime } from 'date-fns-tz' import { enGB, it } from 'date-fns/locale' import { + shortLocale, formatDateLocIsAnnouncement, getCallTimeToDisplayIsAnnouncement, getTimeDifference, @@ -66,53 +67,7 @@ export const CallsDate: FC = ({ ) const currentLanguage = selectedLanguage || i18next?.languages[0] || 'en' - const shortIt = { - ...it, - formatDistance: (token: string, count: number, options?: any) => { - const map: Record = { - xSeconds: 's', - xMinutes: 'm', - xHours: 'h', - xDays: 'g', - xMonths: count === 1 ? ' mese' : ' mesi', - xYears: count === 1 ? ' anno' : ' anni', - } - - const unit = map[token] || '' - const suffix = options?.addSuffix - ? options.comparison && options.comparison > 0 - ? ' tra' - : ' fa' - : '' - - return `${count}${unit}${suffix}` - }, - } - - const shortEn = { - ...enGB, - formatDistance: (token: string, count: number, options?: any) => { - const map: Record = { - xSeconds: 's', - xMinutes: 'm', - xHours: 'h', - xDays: 'd', - xMonths: 'mo', - xYears: 'y', - } - - const unit = map[token] || '' - const suffix = options?.addSuffix - ? options.comparison && options.comparison > 0 - ? ' in' - : ' ago' - : '' - - return `${count}${unit}${suffix}` - }, - } - - const locale = currentLanguage === 'it' ? shortIt : shortEn + const locale = shortLocale(currentLanguage) if (isInAnnouncement) { const dateParts = call?.date_creation.split('/') diff --git a/src/renderer/src/hooks/useChatBridge.ts b/src/renderer/src/hooks/useChatBridge.ts index 53c44dca..f7b96de3 100644 --- a/src/renderer/src/hooks/useChatBridge.ts +++ b/src/renderer/src/hooks/useChatBridge.ts @@ -1,6 +1,7 @@ import { useEffect } from 'react' import { useNethlinkData } from '@renderer/store' import { IPC_EVENTS } from '@shared/constants' +import { contactsFromOperators } from '@nethesis/chat-island' /** Opens a conversation, or the new chat panel, in the chat window. */ export const openChat = (username?: string) => @@ -32,17 +33,11 @@ export function useChatBridge(username?: string) { // Names, avatars, presence and number; sent again once the island is up. useEffect(() => { - const ops: any = operators?.operators || {} - const avatars: any = operators?.avatars || {} - const contacts = Object.values(ops) - .filter((op: any) => op?.username && op.username !== username) - .map((op: any) => ({ - username: op.username, - name: op.name || op.username, - avatar: avatars[op.username], - presence: op.mainPresence, - number: op.endpoints?.mainextension?.[0]?.id, - })) + const contacts = contactsFromOperators( + operators?.operators as any, + operators?.avatars as any, + username || '', + ) if (contacts.length && up) { window.electron.send(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-island-contacts', { contacts, diff --git a/src/renderer/src/lib/dateTime.ts b/src/renderer/src/lib/dateTime.ts index 90fda76f..9cb6666c 100644 --- a/src/renderer/src/lib/dateTime.ts +++ b/src/renderer/src/lib/dateTime.ts @@ -80,3 +80,45 @@ export const getTimeDifference = (account: Account, isInQueue: boolean) => { return differenceValueBetweenTimezone } + +// Short distances, as in the last calls: "15h ago", "2 mesi fa". +const SHORT_UNITS: Record Record> = { + it: (count) => ({ + xSeconds: 's', + xMinutes: 'm', + xHours: 'h', + xDays: 'g', + xMonths: count === 1 ? ' mese' : ' mesi', + xYears: count === 1 ? ' anno' : ' anni', + }), + en: () => ({ + xSeconds: 's', + xMinutes: 'm', + xHours: 'h', + xDays: 'd', + xMonths: 'mo', + xYears: 'y', + }), +} + +/** A date-fns locale for formatDistanceToNowStrict with the short units above. */ +export const shortLocale = (language: string) => { + const itLang = language === 'it' + return { + ...(itLang ? it : enGB), + formatDistance: (token: string, count: number, options?: any) => { + const unit = SHORT_UNITS[itLang ? 'it' : 'en'](count)[token] || '' + const future = options?.comparison && options.comparison > 0 + const suffix = options?.addSuffix + ? itLang + ? future + ? ' tra' + : ' fa' + : future + ? ' in' + : ' ago' + : '' + return `${count}${unit}${suffix}` + }, + } +} From 145734479eeb8024ee2111a038a959472dbb950b Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 1 Oct 2026 10:52:06 +0200 Subject: [PATCH 13/50] chat: operator instead of colleague; island 0.1.10 --- package-lock.json | 8 ++++---- package.json | 2 +- .../Modules/NethVoice/SearchResults/SearchNumber.tsx | 2 +- src/renderer/src/hooks/useChatBridge.ts | 2 +- src/renderer/src/pages/CommandBarPage.tsx | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0af1c376..84f0863a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.9", + "@nethesis/chat-island": "^0.1.10", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.9.tgz", - "integrity": "sha512-ERweHcQRZ5J3ehAj1Fs6Df4QEHnvajxWtzGZt0GKKhWfI+Add+zTOa+webRLVITVbjfmvimieSCGDcC8Gp/+oA==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.10.tgz", + "integrity": "sha512-awpGLSHdqGQhFdaGwCyq1NoAJYqSq3AC4FPeVC3lHLE7fGbNQA/yH7/6/J3i9ZhI0iRiZSEjjwJ/crrRzSdVxQ==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index b298a80d..9adeb9cd 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.9", + "@nethesis/chat-island": "^0.1.10", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx b/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx index 5b574f93..fe59f621 100644 --- a/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx +++ b/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx @@ -130,7 +130,7 @@ export function SearchNumber({ user, className, onClick }: SearchNumberProps) { } />
- {/* A colleague: chat with them */} + {/* An operator: chat with them */} {username && chatStatus === 'online' && ( + {/* The CTI groups' rooms follow the CTI: nobody leaves or deletes them here, as in the CTI. */} + {!c.peer.startsWith('cti-') && ( + + )}
diff --git a/src/shared/types.ts b/src/shared/types.ts index 9273e1d8..c147951e 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -519,6 +519,7 @@ export type ChatConversation = { inactive?: boolean owner?: boolean unread: number + members?: string[] last?: { body: string; ts: number; mine: boolean; nick?: string } } From df7db75098b2c127b5dea1fafcace73639b65cdf Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 8 Oct 2026 08:30:51 +0200 Subject: [PATCH 31/50] chat: island 0.1.31; group looks as in the CTI --- package-lock.json | 8 ++++---- package.json | 2 +- .../Modules/NethVoice/Chat/ChatModule.tsx | 14 +++++++++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8dd3a12a..e5fe1879 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.30", + "@nethesis/chat-island": "^0.1.31", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.30", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.30.tgz", - "integrity": "sha512-v73QlsMNouGNTeMxQi/AwtfwKCnjwxb3AeG+/7g/2er5rfK7Hb/VD/bjUbFwefOi/gkuKduMhTdo65MwivzBRQ==", + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.31.tgz", + "integrity": "sha512-THXpmMjSlcrmAOsOR8obpW3/fhg5H86h7MiQcfAmi2mX+KZATCWuEwOXnXLhuqRcxroUUYjteM/HyRuN2ORZ7A==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 50595357..ac50bcd4 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.30", + "@nethesis/chat-island": "^0.1.31", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx b/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx index ee7be73a..4809fccd 100644 --- a/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx +++ b/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx @@ -5,7 +5,8 @@ import { faRightFromBracket as LeaveIcon, faTrash as DeleteIcon, faTriangleExclamation as WarningIcon, - faUsers as GroupIcon, + faUserGroup as GroupIcon, + faUsers as QueueIcon, } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import i18next, { t } from 'i18next' @@ -167,9 +168,16 @@ export function ChatModule() {
{c.kind === 'group' && !c.avatar ? ( - + // As in the CTI: operator groups (cti-…) blue, a queue's chat with the Queues icon, other groups purple. + From cb6a183109949c498b9cd078587385e2e86f9b61 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Fri, 9 Oct 2026 08:48:03 +0200 Subject: [PATCH 32/50] chat: island 0.1.32 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5fe1879..22d4a25e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.31", + "@nethesis/chat-island": "^0.1.32", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.31.tgz", - "integrity": "sha512-THXpmMjSlcrmAOsOR8obpW3/fhg5H86h7MiQcfAmi2mX+KZATCWuEwOXnXLhuqRcxroUUYjteM/HyRuN2ORZ7A==", + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.32.tgz", + "integrity": "sha512-zkpRdU8dCHlawxDgFmEDN2aTNicRsSnqEdO3wapqyFJ4e5ZBQhHfUMUAvOB+5EyP9/CHbC/wmVhUlSM9Rnd43g==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index ac50bcd4..fba5f26e 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.31", + "@nethesis/chat-island": "^0.1.32", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From cad0927364a5851ba6d797c3df8697f52dc323ff Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 14 Oct 2026 11:07:19 +0200 Subject: [PATCH 33/50] chat: island 0.1.33 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 22d4a25e..ba8cc174 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.32", + "@nethesis/chat-island": "^0.1.33", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.32.tgz", - "integrity": "sha512-zkpRdU8dCHlawxDgFmEDN2aTNicRsSnqEdO3wapqyFJ4e5ZBQhHfUMUAvOB+5EyP9/CHbC/wmVhUlSM9Rnd43g==", + "version": "0.1.33", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.33.tgz", + "integrity": "sha512-6ene8K8lydwPbuIdzV9JQ0so+kyLgt1ePzrBVT9WKbb2iHKDna6VgnYsA5prNf0ppR2kx2gHoAMrwFqUOW2Rzg==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index fba5f26e..af480cc7 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.32", + "@nethesis/chat-island": "^0.1.33", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From a3552aabf6c7da95bae249e63301d3a2d1067d82 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 14 Oct 2026 14:27:10 +0200 Subject: [PATCH 34/50] chat: message icon in the menu, as in the CTI --- .../src/components/Modules/NethVoice/BaseModule/Sidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx b/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx index c3a351d0..44906a6d 100644 --- a/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx +++ b/src/renderer/src/components/Modules/NethVoice/BaseModule/Sidebar.tsx @@ -5,7 +5,7 @@ import { faInfoCircle as InfoMenuIcon, faStar as FavouriteMenuIcon, faSquareParking as ParkedCallMenuIcon, - faCommentDots as ChatMenuIcon, + faMessage as ChatMenuIcon, } from '@fortawesome/free-solid-svg-icons' import { useNethlinkData, useSharedState } from '@renderer/store' import { ParkingType } from '@shared/types' From 89b4e41074af04d264fad06b7e359d9ca2b1f6d0 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 14 Oct 2026 17:19:39 +0200 Subject: [PATCH 35/50] chat: island 0.1.34; the same message icons as the CTI --- package-lock.json | 8 ++++---- package.json | 2 +- .../src/components/Modules/NethVoice/Chat/ChatModule.tsx | 4 ++-- .../src/components/Modules/NethVoice/Chat/icons.ts | 7 +++++++ .../Modules/NethVoice/SearchResults/SearchNumber.tsx | 4 ++-- src/renderer/src/pages/CommandBarPage.tsx | 4 ++-- 6 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 src/renderer/src/components/Modules/NethVoice/Chat/icons.ts diff --git a/package-lock.json b/package-lock.json index ba8cc174..48fe2d02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.33", + "@nethesis/chat-island": "^0.1.34", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.33", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.33.tgz", - "integrity": "sha512-6ene8K8lydwPbuIdzV9JQ0so+kyLgt1ePzrBVT9WKbb2iHKDna6VgnYsA5prNf0ppR2kx2gHoAMrwFqUOW2Rzg==", + "version": "0.1.34", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.34.tgz", + "integrity": "sha512-oi0OKolsspLh0jWeUO3vlmbtj9eIq6Q69gRDnvPooEfSkO1whL8x+GNEp+gd0c9H+plyChehJ1WT6ifxN7Pvcw==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index af480cc7..0a5a1434 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.33", + "@nethesis/chat-island": "^0.1.34", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx b/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx index 4809fccd..9501701a 100644 --- a/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx +++ b/src/renderer/src/components/Modules/NethVoice/Chat/ChatModule.tsx @@ -1,7 +1,6 @@ import { createRef, useState } from 'react' import { - faCommentDots as EmptyIcon, - faCommentMedical as NewChatIcon, + faMessage as EmptyIcon, faRightFromBracket as LeaveIcon, faTrash as DeleteIcon, faTriangleExclamation as WarningIcon, @@ -9,6 +8,7 @@ import { faUsers as QueueIcon, } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faNewChat as NewChatIcon } from './icons' import i18next, { t } from 'i18next' import { format, formatDistanceToNowStrict } from 'date-fns' import { enGB, it } from 'date-fns/locale' diff --git a/src/renderer/src/components/Modules/NethVoice/Chat/icons.ts b/src/renderer/src/components/Modules/NethVoice/Chat/icons.ts new file mode 100644 index 00000000..da12a543 --- /dev/null +++ b/src/renderer/src/components/Modules/NethVoice/Chat/icons.ts @@ -0,0 +1,7 @@ +import type { IconDefinition } from '@fortawesome/fontawesome-svg-core' + +export const faNewChat = { + prefix: 'fas', + iconName: 'new-chat', + icon: [512, 512, [], '', 'M0 352L0 128C0 75 43 32 96 32l320 0c53 0 96 43 96 96l0 224c0 53-43 96-96 96l-120 0c-5.2 0-10.2 1.7-14.4 4.8L166.4 539.2c-4.2 3.1-9.2 4.8-14.4 4.8-13.3 0-24-10.7-24-24l0-72-32 0c-53 0-96-43-96-96zM232 152v64h-64v48h64v64h48v-64h64v-48h-64v-64z'], +} as unknown as IconDefinition diff --git a/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx b/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx index fe59f621..ea888fd4 100644 --- a/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx +++ b/src/renderer/src/components/Modules/NethVoice/SearchResults/SearchNumber.tsx @@ -8,7 +8,7 @@ import { ContactNameAndActions } from '@renderer/components/Modules/NethVoice/Ba import { useFavouriteModule } from '../Speeddials/hook/useFavouriteModule' import { ClassNames } from '@renderer/utils' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faCommentDots } from '@fortawesome/free-solid-svg-icons' +import { faMessage } from '@fortawesome/free-solid-svg-icons' import { openChat } from '@renderer/hooks/useChatBridge' export interface SearchNumberProps { @@ -137,7 +137,7 @@ export function SearchNumber({ user, className, onClick }: SearchNumberProps) { className='self-center ml-2 shrink-0' onClick={() => openChat(username)} > - + {t('Chat.Chat')} )} diff --git a/src/renderer/src/pages/CommandBarPage.tsx b/src/renderer/src/pages/CommandBarPage.tsx index 381536c2..93182f97 100644 --- a/src/renderer/src/pages/CommandBarPage.tsx +++ b/src/renderer/src/pages/CommandBarPage.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faPhone, - faCommentDots, + faMessage, faSearch, faXmark, faUser, @@ -579,7 +579,7 @@ export function CommandBarPage() { className='p-2 rounded-lg text-gray-500 hover:text-primary dark:text-gray-400 dark:hover:text-primaryDark dark:hover:bg-bgDark hover:bg-bgLight' > From 36c0ea5db0a06edcc63e9f1cda26887fa15c76ad Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 14 Oct 2026 17:44:27 +0200 Subject: [PATCH 36/50] chat: island 0.1.35 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48fe2d02..d5ce73a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.34", + "@nethesis/chat-island": "^0.1.35", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.34", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.34.tgz", - "integrity": "sha512-oi0OKolsspLh0jWeUO3vlmbtj9eIq6Q69gRDnvPooEfSkO1whL8x+GNEp+gd0c9H+plyChehJ1WT6ifxN7Pvcw==", + "version": "0.1.35", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.35.tgz", + "integrity": "sha512-qQuWa43aHkblu4YIGV1W/+NW16cikHmezyhM1UgaZowE3t4pcCghWdyG860YZJ+Tgjsum0+H5x+HyNtQ44PT0g==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 0a5a1434..744e063d 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.34", + "@nethesis/chat-island": "^0.1.35", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From fae4e237356c488ccea52b673f090136bde6190d Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Wed, 14 Oct 2026 18:24:17 +0200 Subject: [PATCH 37/50] chat: island 0.1.36 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5ce73a2..a1998c1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.35", + "@nethesis/chat-island": "^0.1.36", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.35", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.35.tgz", - "integrity": "sha512-qQuWa43aHkblu4YIGV1W/+NW16cikHmezyhM1UgaZowE3t4pcCghWdyG860YZJ+Tgjsum0+H5x+HyNtQ44PT0g==", + "version": "0.1.36", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.36.tgz", + "integrity": "sha512-0IFXr3dtLkoe3jNdFxANKdeYr1fe2l1ZdZ03o759DpzX2+dV/leG8PR+xhoDV3aBwpuC9Iu9db4T1t9mHrgw8A==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 744e063d..447030f1 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.35", + "@nethesis/chat-island": "^0.1.36", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From 668b45f36d3cdfcd7c84cb68b814d4d40241e13a Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 15 Oct 2026 11:12:25 +0200 Subject: [PATCH 38/50] chat: island 0.1.37; the window grows from the corner nearest the dock After a drag the dock's corner is kept and the island opens away from it; a click on a head does not move the window. --- package-lock.json | 8 +-- package.json | 2 +- .../controllers/ChatIslandController.ts | 68 ++++++++++++++++--- src/main/lib/ipcEvents.ts | 6 +- src/renderer/src/pages/ChatIslandPage.tsx | 26 +++++-- 5 files changed, 91 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1998c1c..7da72a04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.36", + "@nethesis/chat-island": "^0.1.37", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.36", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.36.tgz", - "integrity": "sha512-0IFXr3dtLkoe3jNdFxANKdeYr1fe2l1ZdZ03o759DpzX2+dV/leG8PR+xhoDV3aBwpuC9Iu9db4T1t9mHrgw8A==", + "version": "0.1.37", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.37.tgz", + "integrity": "sha512-txCw7ED6Q95eh8yxmG3YnJkLzUOtZLO867q4lvfxTbV7rdZgszini22awX93NoWdE+pE2DFZA+fgcOVbkxcamw==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 447030f1..f9262f4a 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.36", + "@nethesis/chat-island": "^0.1.37", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/main/classes/controllers/ChatIslandController.ts b/src/main/classes/controllers/ChatIslandController.ts index e9ae3316..bd58529b 100644 --- a/src/main/classes/controllers/ChatIslandController.ts +++ b/src/main/classes/controllers/ChatIslandController.ts @@ -1,24 +1,45 @@ import { ChatIslandWindow } from '../windows' import { Log } from '@shared/utils/logger' +import { IPC_EVENTS } from '@shared/constants' import { screen } from 'electron' +type Corner = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' +type Rect = { x: number; y: number; w: number; h: number } + +// Between the window's edge and the dock: the island's right-4/left-4, and its bottom-5/top-5 plus the dock's 0.75rem margin. +const SIDE = 16 +const END = 32 + export class ChatIslandController { static instance: ChatIslandController | undefined window: ChatIslandWindow private wantFocus = false private focusTimer: ReturnType | undefined - // Distance from the work area's bottom-right corner, kept after a drag, and that display. - private anchor = { right: 0, bottom: 0 } + // The work area's corner nearest the dock, and the window's distance from its two edges, kept after a drag. + private corner: Corner = 'bottom-right' + private anchor = { x: 0, y: 0 } private displayId: number | undefined + private size: { w: number; h: number; dock?: Rect; corner?: Corner } = { + w: 0, + h: 0, + } constructor() { ChatIslandController.instance = this this.window = new ChatIslandWindow() } - // Sized to the island, grown from its bottom-right corner; hidden when there is nothing to show. - resize(size: { w: number; h: number }) { + // Sized to the island, grown from the corner nearest the dock; hidden when there is nothing to show. + resize(size: { w: number; h: number; dock?: Rect; corner?: Corner }) { try { + this.size = size + // A reloaded island starts from the default corner: tell it the current one. + if (size.corner && size.corner !== this.corner) + this.window.emit( + IPC_EVENTS.CHAT_TO_ISLAND, + 'chat-island-corner', + this.corner, + ) const window = this.window.getWindow() if (!window) return if (size.w < 8 || size.h < 8) { @@ -28,9 +49,15 @@ export class ChatIslandController { const { x, y, width, height } = this.workArea() const w = Math.min(Math.ceil(size.w), width) const h = Math.min(Math.ceil(size.h), height) + const left = this.corner.endsWith('left') + ? x + this.anchor.x + : x + width - this.anchor.x - w + const top = this.corner.startsWith('top') + ? y + this.anchor.y + : y + height - this.anchor.y - h window.setBounds({ - x: Math.max(x, x + width - this.anchor.right - w), - y: Math.max(y, y + height - this.anchor.bottom - h), + x: Math.min(Math.max(x, left), x + width - w), + y: Math.min(Math.max(y, top), y + height - h), width: w, height: h, }) @@ -53,16 +80,39 @@ export class ChatIslandController { return (d ?? screen.getPrimaryDisplay()).workArea } - // After a drag: the new corner is where the island grows from. + // After a drag: the corner nearest the dock is where the island grows from, as in the CTI. keepPosition() { const window = this.window.getWindow() if (!window) return const b = window.getBounds() this.displayId = screen.getDisplayMatching(b).id const { x, y, width, height } = this.workArea() + // The dock sits in the window's corner: its place follows from the bounds, only its size is measured. + const w = this.size.dock?.w ?? b.width - 2 * SIDE + const h = this.size.dock?.h ?? b.height - 2 * END + const dock = { + x: this.corner.endsWith('left') ? b.x + SIDE : b.x + b.width - SIDE - w, + y: this.corner.startsWith('top') ? b.y + END : b.y + b.height - END - h, + w, + h, + } + const left = dock.x + dock.w / 2 < x + width / 2 + const top = dock.y + dock.h / 2 < y + height / 2 + const corner: Corner = `${top ? 'top' : 'bottom'}-${left ? 'left' : 'right'}` this.anchor = { - right: Math.max(0, x + width - b.x - b.width), - bottom: Math.max(0, y + height - b.y - b.height), + x: Math.max( + 0, + left ? dock.x - SIDE - x : x + width - dock.x - dock.w - SIDE, + ), + y: Math.max( + 0, + top ? dock.y - END - y : y + height - dock.y - dock.h - END, + ), + } + if (corner !== this.corner) { + this.corner = corner + this.window.emit(IPC_EVENTS.CHAT_TO_ISLAND, 'chat-island-corner', corner) + this.resize(this.size) } } diff --git a/src/main/lib/ipcEvents.ts b/src/main/lib/ipcEvents.ts index d6e2b336..f2589d63 100644 --- a/src/main/lib/ipcEvents.ts +++ b/src/main/lib/ipcEvents.ts @@ -237,7 +237,11 @@ export function registerIpcEvents() { const cursorPosition = screen.getCursorScreenPoint() const deltaX = cursorPosition.x - draggingWindow.startMousePosition.x const deltaY = cursorPosition.y - draggingWindow.startMousePosition.y - if (window.title === PAGES.CHATISLAND) { + // A click on a head is not a move: the window stays where it grew from. + if ( + window.title === PAGES.CHATISLAND && + (Math.abs(deltaX) > 3 || Math.abs(deltaY) > 3) + ) { ChatIslandController.instance?.keepPosition() } if (window.title === PAGES.PHONEISLAND) { diff --git a/src/renderer/src/pages/ChatIslandPage.tsx b/src/renderer/src/pages/ChatIslandPage.tsx index a88c6ba3..6e61c077 100644 --- a/src/renderer/src/pages/ChatIslandPage.tsx +++ b/src/renderer/src/pages/ChatIslandPage.tsx @@ -17,6 +17,10 @@ export function ChatIslandPage() { const [account] = useSharedState('account') const [theme] = useSharedState('theme') const [enabled, setEnabled] = useState(false) + // The screen corner nearest the dock, chosen by NethLink after a drag: panels open away from it. + const [corner, setCorner] = useState< + 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' + >('bottom-right') const allowed = !!account?.data?.profile?.macro_permissions?.nethvoice_cti?.permissions @@ -70,22 +74,32 @@ export function ChatIslandPage() { window.electron.send(IPC_EVENTS.CHAT_ISLAND_RESIZE, { w: 0, h: 0 }) return } - observer = new ResizeObserver(() => { + // The size, and where the dock is in the window (NethLink picks the corner from it). + const send = () => { const { width, height } = root.getBoundingClientRect() + const d = root.lastElementChild?.getBoundingClientRect() window.electron.send( IPC_EVENTS.CHAT_ISLAND_RESIZE, width < 8 ? { w: 0, h: 0 } - : { w: width + 16 + PAD, h: height + 20 + PAD }, + : { + w: width + 16 + PAD, + h: height + 20 + PAD, + dock: d && { x: d.x, y: d.y, w: d.width, h: d.height }, + corner, + }, ) - }) + } + observer = new ResizeObserver(send) observer.observe(root) + if (root.lastElementChild) observer.observe(root.lastElementChild) }, 200) return () => { clearInterval(timer) observer?.disconnect() } - }, [on]) + // A new corner moves the dock inside the window without resizing it: observe again, which reports at once. + }, [on, corner]) // Events between the island and NethLink. useEffect(() => { @@ -126,10 +140,12 @@ export function ChatIslandPage() { } const error = (e: Event) => Log.warning('chat island', (e as CustomEvent).detail) + const moved = (e: Event) => setCorner((e as CustomEvent).detail) OUT.forEach((n) => window.addEventListener(n, forward)) window.addEventListener('chat-island-call', call) window.addEventListener('chat-island-notify', notify) window.addEventListener('chat-island-error', error) + window.addEventListener('chat-island-corner', moved) return () => { // Chat off: NethLink and the command bar must not keep showing it online. window.electron.send(IPC_EVENTS.CHAT_FROM_ISLAND, 'chat-island-status', { @@ -140,6 +156,7 @@ export function ChatIslandPage() { window.removeEventListener('chat-island-call', call) window.removeEventListener('chat-island-notify', notify) window.removeEventListener('chat-island-error', error) + window.removeEventListener('chat-island-corner', moved) } }, [on]) @@ -187,6 +204,7 @@ export function ChatIslandPage() { Date: Thu, 15 Oct 2026 11:50:56 +0200 Subject: [PATCH 39/50] chat: island 0.1.38 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7da72a04..9413fbb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.37", + "@nethesis/chat-island": "^0.1.38", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.37", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.37.tgz", - "integrity": "sha512-txCw7ED6Q95eh8yxmG3YnJkLzUOtZLO867q4lvfxTbV7rdZgszini22awX93NoWdE+pE2DFZA+fgcOVbkxcamw==", + "version": "0.1.38", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.38.tgz", + "integrity": "sha512-NpsRHQEEFNI7JLFTkPUfxsbeXirbdL3Zpd8He2F+nPklgBvjUsjZZBMN93+xXdO9dudFqsTrv9yu9OanrEG3Pg==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index f9262f4a..8d2d8056 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.37", + "@nethesis/chat-island": "^0.1.38", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From edb62e79e80f6177d38797c00879ddc8db798e9a Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 15 Oct 2026 12:24:11 +0200 Subject: [PATCH 40/50] chat: island 0.1.39 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9413fbb7..8547aa58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.38", + "@nethesis/chat-island": "^0.1.39", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.38", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.38.tgz", - "integrity": "sha512-NpsRHQEEFNI7JLFTkPUfxsbeXirbdL3Zpd8He2F+nPklgBvjUsjZZBMN93+xXdO9dudFqsTrv9yu9OanrEG3Pg==", + "version": "0.1.39", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.39.tgz", + "integrity": "sha512-wxESvUm+SmO0pkul5r+1n/MsUBTeE8E3HAiBBiT0+SGQpJZ0mJdXjbViNx5KrWrrxb3LR8z9TEnj5KwRgc5org==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 8d2d8056..ecb6de93 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.38", + "@nethesis/chat-island": "^0.1.39", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From 5900d8441a0ba83ab04b8f81530a06436b2f960d Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 15 Oct 2026 13:58:55 +0200 Subject: [PATCH 41/50] chat-island 0.1.40 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8547aa58..fc0f7206 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.39", + "@nethesis/chat-island": "^0.1.40", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.39", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.39.tgz", - "integrity": "sha512-wxESvUm+SmO0pkul5r+1n/MsUBTeE8E3HAiBBiT0+SGQpJZ0mJdXjbViNx5KrWrrxb3LR8z9TEnj5KwRgc5org==", + "version": "0.1.40", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.40.tgz", + "integrity": "sha512-AeJGn0FP4prQi+GoCrT+tIcGic3Pe6JVIlGi7R2rye17h+l+fFHAZf9+FFZ47Lv21cJXTD8ftSRdYdHcHtSDwg==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index ecb6de93..8e129bea 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.39", + "@nethesis/chat-island": "^0.1.40", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From 51792d1336b1c4503df4d8a00fec9af239090ac1 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 15 Oct 2026 15:00:35 +0200 Subject: [PATCH 42/50] chat: blue accent, registered devices for the island, chat-island 0.1.41 --- package-lock.json | 8 ++++---- package.json | 2 +- src/main/classes/controllers/ChatIslandController.ts | 2 +- src/renderer/src/hooks/useChatBridge.ts | 1 + src/renderer/src/pages/ChatIslandPage.tsx | 1 + 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc0f7206..017dd6cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.40", + "@nethesis/chat-island": "^0.1.41", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.40", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.40.tgz", - "integrity": "sha512-AeJGn0FP4prQi+GoCrT+tIcGic3Pe6JVIlGi7R2rye17h+l+fFHAZf9+FFZ47Lv21cJXTD8ftSRdYdHcHtSDwg==", + "version": "0.1.41", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.41.tgz", + "integrity": "sha512-jzxTQ6NqXGa+jFkOOLzsLXB2LojJ5OA8xkl8MUWZE+ptg5iO13qJaw/WvlNOyupheWHsw+p68iZdiHConW4Nww==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 8e129bea..c45351b8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.40", + "@nethesis/chat-island": "^0.1.41", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/main/classes/controllers/ChatIslandController.ts b/src/main/classes/controllers/ChatIslandController.ts index bd58529b..457feb3f 100644 --- a/src/main/classes/controllers/ChatIslandController.ts +++ b/src/main/classes/controllers/ChatIslandController.ts @@ -6,7 +6,7 @@ import { screen } from 'electron' type Corner = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' type Rect = { x: number; y: number; w: number; h: number } -// Between the window's edge and the dock: the island's right-4/left-4, and its bottom-5/top-5 plus the dock's 0.75rem margin. +// Between the window's edge and the dock: the island's right-4/left-4 and bottom-8/top-8. const SIDE = 16 const END = 32 diff --git a/src/renderer/src/hooks/useChatBridge.ts b/src/renderer/src/hooks/useChatBridge.ts index fe99d64d..ac9ef9b5 100644 --- a/src/renderer/src/hooks/useChatBridge.ts +++ b/src/renderer/src/hooks/useChatBridge.ts @@ -43,6 +43,7 @@ export function useChatBridge(username?: string) { operators?.operators as any, operators?.avatars as any, username || '', + operators?.extensions as any, ) if (!contacts.length) return // Compared by content: the shared state may hand over a new object with the same avatars. diff --git a/src/renderer/src/pages/ChatIslandPage.tsx b/src/renderer/src/pages/ChatIslandPage.tsx index 6e61c077..34119cfa 100644 --- a/src/renderer/src/pages/ChatIslandPage.tsx +++ b/src/renderer/src/pages/ChatIslandPage.tsx @@ -211,6 +211,7 @@ export function ChatIslandPage() { maxHeads={5} notifications='auto' nativeTooltips + accent='blue' /> ) From 36d99f3035ecd6966e9abd9aa5e2c0442b859312 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 15 Oct 2026 15:16:48 +0200 Subject: [PATCH 43/50] chat-island 0.1.42 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 017dd6cc..4d029bc1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.41", + "@nethesis/chat-island": "^0.1.42", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.41", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.41.tgz", - "integrity": "sha512-jzxTQ6NqXGa+jFkOOLzsLXB2LojJ5OA8xkl8MUWZE+ptg5iO13qJaw/WvlNOyupheWHsw+p68iZdiHConW4Nww==", + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.42.tgz", + "integrity": "sha512-v60pzAgzYwBEeAyjVNtTz0ci435wxgoqJ318pPgDuFcl7+gtxgGOM+Tz2+PPzSTgg3NhMLuJrG3+CuZo4b/rlA==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index c45351b8..1d6de78a 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.41", + "@nethesis/chat-island": "^0.1.42", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From 5fb0eabf411d13450105f7c595b680035511cf6d Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 15 Oct 2026 15:54:15 +0200 Subject: [PATCH 44/50] chat-island 0.1.43 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d029bc1..4cc92f2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.42", + "@nethesis/chat-island": "^0.1.43", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.42", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.42.tgz", - "integrity": "sha512-v60pzAgzYwBEeAyjVNtTz0ci435wxgoqJ318pPgDuFcl7+gtxgGOM+Tz2+PPzSTgg3NhMLuJrG3+CuZo4b/rlA==", + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.43.tgz", + "integrity": "sha512-/2yY1fCYPa9yIYom846MzpSb2vdU6duDuriqsgCITmA+n5gOV26L7EmKl2OTXU7XIgmTlpwxSHJTNnG+pmIe+A==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 1d6de78a..3f6e60f9 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.42", + "@nethesis/chat-island": "^0.1.43", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From 628c0dbcf1a8e88ea0e300f21e3f0b0443715738 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 15 Oct 2026 16:23:57 +0200 Subject: [PATCH 45/50] chat: island in NethLink's language, chat-island 0.1.44 --- package-lock.json | 8 ++++---- package.json | 2 +- src/renderer/src/pages/ChatIslandPage.tsx | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4cc92f2d..a2ccc3c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.43", + "@nethesis/chat-island": "^0.1.44", "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", @@ -2526,9 +2526,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.43.tgz", - "integrity": "sha512-/2yY1fCYPa9yIYom846MzpSb2vdU6duDuriqsgCITmA+n5gOV26L7EmKl2OTXU7XIgmTlpwxSHJTNnG+pmIe+A==", + "version": "0.1.44", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.44.tgz", + "integrity": "sha512-8Yo/7cbLg5E+4U/HVQPr7mN/IOPGccAbJLLi24sm1X3q2TYofKKFi7mAEf7hCY18pXudHnlI52+UpHXzgdDbYw==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 3f6e60f9..b55f0e4d 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.43", + "@nethesis/chat-island": "^0.1.44", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", diff --git a/src/renderer/src/pages/ChatIslandPage.tsx b/src/renderer/src/pages/ChatIslandPage.tsx index 34119cfa..b0e2bf0e 100644 --- a/src/renderer/src/pages/ChatIslandPage.tsx +++ b/src/renderer/src/pages/ChatIslandPage.tsx @@ -1,4 +1,5 @@ import { ChatIsland } from '@nethesis/chat-island' +import i18next from 'i18next' import { useSharedState } from '@renderer/store' import { IPC_EVENTS } from '@shared/constants' import { Log } from '@shared/utils/logger' @@ -212,6 +213,7 @@ export function ChatIslandPage() { notifications='auto' nativeTooltips accent='blue' + language={i18next.language} /> ) From 1705200d034547d7ea21136d911800a79cd78bd3 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Thu, 15 Oct 2026 16:25:18 +0200 Subject: [PATCH 46/50] lockfile on main --- package-lock.json | 684 +--------------------------------------------- 1 file changed, 2 insertions(+), 682 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2ccc3c2..1fedb150 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,6 @@ "win-ca": "^3.5.1" }, "devDependencies": { - "@date-fns/utc": "^2.0.0", "@electron-toolkit/eslint-config-prettier": "^3.0.0", "@electron-toolkit/eslint-config-ts": "^3.1.0", "@electron-toolkit/preload": "^3.0.0", @@ -29,8 +28,6 @@ "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", "@nethesis/chat-island": "^0.1.44", - "@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands", - "@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", @@ -39,12 +36,10 @@ "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.2.1", - "auto-launch": "^5.0.6", "autoprefixer": "^10.4.17", "axios": "^1.6.7", "classnames": "^2.5.1", "clsx": "^2.1.0", - "crypto-browserify": "^3.12.0", "crypto-js": "^4.2.0", "date-fns": "^2.30.0", "date-fns-tz": "^1.3.8", @@ -57,13 +52,10 @@ "eslint-plugin-react-hooks": "^5.2.0", "framer-motion": "^11.11.8", "i18next": "^22.4.9", - "i18next-browser-languagedetector": "^7.0.1", "i18next-electron-fs-backend": "^3.0.1", "i18next-fs-backend": "^2.3.2", - "i18next-http-backend": "^2.1.1", "lodash": "^4.17.21", "moment": "^2.30.1", - "motion": "^11.13.1", "path-browserify": "^1.0.1", "postcss": "^8.4.35", "prettier": "^3.2.4", @@ -73,13 +65,11 @@ "react-hook-form": "^7.50.1", "react-i18next": "^12.1.5", "react-router-dom": "^6.21.3", - "rollup": "^4.12.1", + "react-tooltip": "^5.28.0", "tailwind-merge": "^2.2.1", - "tailwind-scrollbar": "^3.1.0", "tailwindcss": "^3.4.1", "typescript": "^5.3.3", "vite": "^5.0.12", - "vite-plugin-copy": "^0.1.6", "zod": "^3.22.4", "zustand": "^4.5.0" }, @@ -464,13 +454,6 @@ "node": ">=6.9.0" } }, - "node_modules/@date-fns/utc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@date-fns/utc/-/utc-2.1.1.tgz", - "integrity": "sha512-SlJDfG6RPeEX8wEVv6ZB3kak4MmbtyiI2qX/5zuKdordbrhB/iaJ58GVMZgJ6P1sJaM1gMgENFYYeg1JWrCFrA==", - "dev": true, - "license": "MIT" - }, "node_modules/@electron-toolkit/eslint-config-prettier": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@electron-toolkit/eslint-config-prettier/-/eslint-config-prettier-3.0.1.tgz", @@ -2541,54 +2524,6 @@ "react-dom": "^18.2.0 || ^19.0.0" } }, - "node_modules/@nethesis/nethesis-brands-svg-icons": { - "version": "6.2.1", - "resolved": "git+ssh://git@github.com/nethesis/Font-Awesome.git#dbcf431acf0e504145486c9ac70f14946279e2e7", - "dev": true, - "hasInstallScript": true, - "license": "UNLICENSED", - "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@nethesis/nethesis-brands-svg-icons/node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", - "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/@nethesis/nethesis-light-svg-icons": { - "version": "6.2.1", - "resolved": "git+ssh://git@github.com/nethesis/Font-Awesome.git#3e110fb0ae63495fb8b7ca9811e5f07eed1ac962", - "dev": true, - "hasInstallScript": true, - "license": "UNLICENSED", - "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@nethesis/nethesis-light-svg-icons/node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", - "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/@nethesis/nethesis-solid-svg-icons": { "version": "6.2.1", "resolved": "git+ssh://git@github.com/nethesis/Font-Awesome.git#1a6b58a7581627785d4a4cbc0314ed3d185a1288", @@ -5279,12 +5214,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/applescript": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/applescript/-/applescript-1.0.0.tgz", - "integrity": "sha512-yvtNHdWvtbYEiIazXAdp/NY+BBb65/DAseqlNiJQjOx9DynuzOYDbVLBJvuc0ve0VL9x6B3OHF6eH52y9hCBtQ==", - "dev": true - }, "node_modules/arch": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", @@ -5465,25 +5394,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "dev": true, - "license": "MIT" - }, "node_modules/asn1js": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", @@ -5563,23 +5473,6 @@ "node": ">= 4.0.0" } }, - "node_modules/auto-launch": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/auto-launch/-/auto-launch-5.0.6.tgz", - "integrity": "sha512-OgxiAm4q9EBf9EeXdPBiVNENaWE3jUZofwrhAkWjHDYGezu1k3FRZHU8V2FBxGuSJOHzKmTJEd0G7L7/0xDGFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "applescript": "^1.0.0", - "mkdirp": "^0.5.1", - "path-is-absolute": "^1.0.0", - "untildify": "^3.0.2", - "winreg": "1.2.4" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/autoprefixer": { "version": "10.6.1", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.6.1.tgz", @@ -5745,13 +5638,6 @@ "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==", "license": "MIT" }, - "node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "dev": true, - "license": "MIT" - }, "node_modules/boolean": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", @@ -5791,89 +5677,6 @@ "node": ">=8" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", - "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", - "dev": true, - "license": "ISC", - "dependencies": { - "bn.js": "^5.2.2", - "browserify-rsa": "^4.1.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.6.1", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.9", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/browserslist": { "version": "4.29.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", @@ -5949,13 +5752,6 @@ "dev": true, "license": "MIT" }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "dev": true, - "license": "MIT" - }, "node_modules/builder-util": { "version": "26.16.0", "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.16.0.tgz", @@ -6305,20 +6101,6 @@ "node": ">=8" } }, - "node_modules/cipher-base": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", - "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", @@ -6597,53 +6379,6 @@ "buffer": "^5.1.0" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, "node_modules/cross-dirname": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", @@ -6653,16 +6388,6 @@ "optional": true, "peer": true }, - "node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -6678,33 +6403,6 @@ "node": ">= 8" } }, - "node_modules/crypto-browserify": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserify-cipher": "^1.0.1", - "browserify-sign": "^4.2.3", - "create-ecdh": "^4.0.4", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "diffie-hellman": "^5.0.3", - "hash-base": "~3.0.4", - "inherits": "^2.0.4", - "pbkdf2": "^3.1.2", - "public-encrypt": "^4.0.3", - "randombytes": "^2.1.0", - "randomfill": "^1.0.4" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", @@ -6962,17 +6660,6 @@ "node": ">=6" } }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -6998,25 +6685,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "dev": true, - "license": "MIT" - }, "node_modules/dir-compare": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", @@ -7527,29 +7195,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "dev": true, - "license": "MIT" - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -8213,17 +7858,6 @@ "node": ">=0.8.x" } }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, "node_modules/exif-parser": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", @@ -9047,31 +8681,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hash-base": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", - "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hasown": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", @@ -9085,18 +8694,6 @@ "node": ">= 0.4" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -9268,16 +8865,6 @@ "dev": true, "license": "MIT" }, - "node_modules/i18next-http-backend": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.7.3.tgz", - "integrity": "sha512-FgZxrXdRA5u44xfYsJlEBL4/KH3f2IluBpgV/7riW0YW2VEyM8FzVt2XHAOi6id0Ppj7vZvCZVpp5LrGXnc8Ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-fetch": "4.0.0" - } - }, "node_modules/iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -10513,18 +10100,6 @@ "node": ">= 0.4" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -10558,27 +10133,6 @@ "node": ">=8.6" } }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "dev": true, - "license": "MIT" - }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -10654,20 +10208,6 @@ "mini-svg-data-uri": "cli.js" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true, - "license": "MIT" - }, "node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", @@ -10723,6 +10263,7 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -10740,33 +10281,6 @@ "node": "*" } }, - "node_modules/motion": { - "version": "11.18.2", - "resolved": "https://registry.npmjs.org/motion/-/motion-11.18.2.tgz", - "integrity": "sha512-JLjvFDuFr42NFtcVoMAyC2sEjnpA8xpy6qWPyzQvCloznAyQ8FIXioxWfHiLtgYhoVpfUqSWpn1h9++skj9+Wg==", - "dev": true, - "license": "MIT", - "dependencies": { - "framer-motion": "^11.18.2", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "@emotion/is-prop-valid": "*", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/is-prop-valid": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, "node_modules/motion-dom": { "version": "11.18.1", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", @@ -11322,23 +10836,6 @@ "node": ">=6" } }, - "node_modules/parse-asn1": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", - "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "pbkdf2": "^3.1.5", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/parse-bmfont-ascii": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", @@ -11454,24 +10951,6 @@ "dev": true, "license": "ISC" }, - "node_modules/pbkdf2": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", - "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "ripemd160": "^2.0.3", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.12", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/pe-library": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", @@ -12024,28 +11503,6 @@ "node": ">=10" } }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "dev": true, - "license": "MIT" - }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -12127,27 +11584,6 @@ "dev": true, "license": "MIT" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -12758,36 +12194,6 @@ "rimraf": "bin.js" } }, - "node_modules/ripemd160": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", - "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^3.1.2", - "inherits": "^2.0.4" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/ripemd160/node_modules/hash-base": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", - "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -13137,27 +12543,6 @@ "node": ">= 0.4" } }, - "node_modules/sha.js": { - "version": "2.4.12", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", - "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", - "dev": true, - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.0" - }, - "bin": { - "sha.js": "bin.js" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -13924,19 +13309,6 @@ "url": "https://github.com/sponsors/dcastil" } }, - "node_modules/tailwind-scrollbar": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tailwind-scrollbar/-/tailwind-scrollbar-3.1.0.tgz", - "integrity": "sha512-pmrtDIZeHyu2idTejfV59SbaJyvp1VRjYxAjZBH0jnyrPRo6HL1kD5Glz8VPagasqr6oAx6M05+Tuw429Z8jxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "tailwindcss": "3.x" - } - }, "node_modules/tailwindcss": { "version": "3.4.19", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", @@ -14229,28 +13601,6 @@ "tmp": "^0.2.0" } }, - "node_modules/to-buffer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", - "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/to-buffer/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -14522,16 +13872,6 @@ "node": ">= 4.0.0" } }, - "node_modules/untildify": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", - "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/unzipper": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.12.5.tgz", @@ -14751,19 +14091,6 @@ } } }, - "node_modules/vite-plugin-copy": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/vite-plugin-copy/-/vite-plugin-copy-0.1.6.tgz", - "integrity": "sha512-bqIaefZOE2Jx8P5wJuHKL5GzCERa/pcwdUQWaocyTNXgalN2xkxXH7LmqRJ34V2OlKF2F9E/zj0zITS7U6PpUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-glob": "^3.2.7" - }, - "engines": { - "node": ">=14.8.0" - } - }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -14970,13 +14297,6 @@ "node": ">=4" } }, - "node_modules/winreg": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz", - "integrity": "sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA==", - "dev": true, - "license": "BSD-2-Clause" - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", From c713b412af87283f8ce6ba0bd87682a39750f758 Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Fri, 16 Oct 2026 08:45:26 +0200 Subject: [PATCH 47/50] chat: the dock's tooltips in the page, the window widens to show them (a native one fell behind the screen-saver level window) --- src/renderer/src/pages/ChatIslandPage.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/renderer/src/pages/ChatIslandPage.tsx b/src/renderer/src/pages/ChatIslandPage.tsx index b0e2bf0e..c7d4f7ca 100644 --- a/src/renderer/src/pages/ChatIslandPage.tsx +++ b/src/renderer/src/pages/ChatIslandPage.tsx @@ -64,12 +64,14 @@ export function ChatIslandPage() { } let observer: ResizeObserver | undefined let watched: Element | null = null + let unhover = () => {} // The island may replace its root: watch whichever one is in the page. const timer = setInterval(() => { const root = document.querySelector('.chat-island-root') if (root === watched) return observer?.disconnect() observer = undefined + unhover() watched = root if (!root) { window.electron.send(IPC_EVENTS.CHAT_ISLAND_RESIZE, { w: 0, h: 0 }) @@ -77,8 +79,14 @@ export function ChatIslandPage() { } // The size, and where the dock is in the window (NethLink picks the corner from it). const send = () => { - const { width, height } = root.getBoundingClientRect() + const r = root.getBoundingClientRect() const d = root.lastElementChild?.getBoundingClientRect() + // A head's tooltip sticks out of the island toward the screen: the window widens to show it. + const t = [...root.querySelectorAll('[role=tooltip]')] + .find((e) => e.getClientRects().length) + ?.getBoundingClientRect() + const width = r.width + (t ? Math.max(0, r.left - t.left, t.right - r.right) : 0) + const { height } = r window.electron.send( IPC_EVENTS.CHAT_ISLAND_RESIZE, width < 8 @@ -92,12 +100,19 @@ export function ChatIslandPage() { ) } observer = new ResizeObserver(send) + root.addEventListener('mouseover', send) + root.addEventListener('mouseout', send) + unhover = () => { + root.removeEventListener('mouseover', send) + root.removeEventListener('mouseout', send) + } observer.observe(root) if (root.lastElementChild) observer.observe(root.lastElementChild) }, 200) return () => { clearInterval(timer) observer?.disconnect() + unhover() } // A new corner moves the dock inside the window without resizing it: observe again, which reports at once. }, [on, corner]) @@ -211,7 +226,6 @@ export function ChatIslandPage() { newChatButton={false} maxHeads={5} notifications='auto' - nativeTooltips accent='blue' language={i18next.language} /> From b57c231db04e29faeb72f01b4c4d095646ca5f4a Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Fri, 16 Oct 2026 08:45:26 +0200 Subject: [PATCH 48/50] chat: chat-island 0.1.45 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1fedb150..f7245d11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.44", + "@nethesis/chat-island": "^0.1.45", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", @@ -2509,9 +2509,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.44", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.44.tgz", - "integrity": "sha512-8Yo/7cbLg5E+4U/HVQPr7mN/IOPGccAbJLLi24sm1X3q2TYofKKFi7mAEf7hCY18pXudHnlI52+UpHXzgdDbYw==", + "version": "0.1.45", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.45.tgz", + "integrity": "sha512-aT5grIaMpfrr982QPKkE8JzPXFIn9nziEyzy92dhocKxb6+JQygHtwAe+6DKh8lGlJA3ff+A+sOGSNaziLSgkg==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index b55f0e4d..e5a05299 100644 --- a/package.json +++ b/package.json @@ -45,8 +45,8 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", + "@nethesis/chat-island": "^0.1.45", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", - "@nethesis/chat-island": "^0.1.44", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", "@types/lodash": "^4.14.202", From fe2bc9235a065454236bcd05620797c61e1520ef Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Fri, 16 Oct 2026 09:37:18 +0200 Subject: [PATCH 49/50] chat: chat-island 0.1.46 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index f7245d11..dfff06d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.45", + "@nethesis/chat-island": "^0.1.46", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", @@ -2509,9 +2509,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.45", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.45.tgz", - "integrity": "sha512-aT5grIaMpfrr982QPKkE8JzPXFIn9nziEyzy92dhocKxb6+JQygHtwAe+6DKh8lGlJA3ff+A+sOGSNaziLSgkg==", + "version": "0.1.46", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.46.tgz", + "integrity": "sha512-MglDg7SIGPMIffr1ts9HGE48k6k/4BgmLl+krNNj+Eoo646GmAIRnOq2z26VJ73thwdjZ/gck3W/OqtSlmULGg==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index e5a05299..b925d230 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.45", + "@nethesis/chat-island": "^0.1.46", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", From 32debaaf995386745b65710d012204b3d32dfe8a Mon Sep 17 00:00:00 2001 From: Edoardo Spadoni Date: Fri, 16 Oct 2026 14:30:13 +0200 Subject: [PATCH 50/50] chat: chat-island 0.1.47 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index dfff06d3..6236fe2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.46", + "@nethesis/chat-island": "^0.1.47", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7", @@ -2509,9 +2509,9 @@ } }, "node_modules/@nethesis/chat-island": { - "version": "0.1.46", - "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.46.tgz", - "integrity": "sha512-MglDg7SIGPMIffr1ts9HGE48k6k/4BgmLl+krNNj+Eoo646GmAIRnOq2z26VJ73thwdjZ/gck3W/OqtSlmULGg==", + "version": "0.1.47", + "resolved": "https://registry.npmjs.org/@nethesis/chat-island/-/chat-island-0.1.47.tgz", + "integrity": "sha512-fYb26n34ZHaecvEOUcKwFyT2iIWy2aAfFrJyPl9JG5q6Ra6nc9QoN78VOwtENDLZGurArHlcTF+6Mk+ho2CaQA==", "dev": true, "license": "AGPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index b925d230..e8423a11 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@headlessui/react": "^2.2.8", "@hookform/resolvers": "^3.3.4", - "@nethesis/chat-island": "^0.1.46", + "@nethesis/chat-island": "^0.1.47", "@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid", "@nethesis/phone-island": "^1.0.15", "@tailwindcss/forms": "^0.5.7",