mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-10-05 22:05:50 +01:00
Patch: Various fixes (#660)
Various fixes from the last couple days: - Add manual approval option for book/audiobook requests (#651) - Add flagged HTTP headers - Add filesystem fallback - copy + delete when hardlink/move fails across filesystems (#647) - Dependency updates - Tweak frontend test config (simplified tsconfig for tests) - Fix overlapping sort scoring in release modal - duplicate scoring keys caused incorrect release ordering (#654 ) - Fix stale search session after download - search state was not refreshed when returning from a download (#659) - Fix multi-format release filtering - releases with multiple formats were incorrectly excluded by the format filter (#658) - Fix config persistence when action button is used - clicking "Test connection" reset unsaved settings (#657) - Fix request grid text positioning in admin request policy panel - Fix rTorrent path discovery (#653) - Fix `/login` API check (#650)
This commit is contained in:
Generated
+75
-530
@@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.30.2",
|
||||
"react-router-dom": "^6.30.3",
|
||||
"socket.io-client": "^4.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -69,6 +69,7 @@
|
||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
@@ -711,24 +712,6 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^5.1.2",
|
||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
||||
"strip-ansi": "^7.0.1",
|
||||
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
|
||||
"wrap-ansi": "^8.1.0",
|
||||
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||
@@ -817,21 +800,10 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.23.1",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.1.tgz",
|
||||
"integrity": "sha512-vDbaOzF7yT2Qs4vO6XV1MHcJv+3dgR1sT+l3B8xxOVhUC336prMvqrvsLL/9Dnw2xr6Qhz4J0dmS0llNAbnUmQ==",
|
||||
"version": "1.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz",
|
||||
"integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
@@ -1216,6 +1188,7 @@
|
||||
"integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
@@ -1233,6 +1206,7 @@
|
||||
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@@ -1269,32 +1243,6 @@
|
||||
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
|
||||
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
||||
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/any-promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
@@ -1361,13 +1309,6 @@
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.8.25",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz",
|
||||
@@ -1391,16 +1332,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
@@ -1434,6 +1365,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.19",
|
||||
"caniuse-lite": "^1.0.30001751",
|
||||
@@ -1517,26 +1449,6 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
@@ -1554,21 +1466,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
@@ -1621,13 +1518,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.249",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.249.tgz",
|
||||
@@ -1635,13 +1525,6 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
|
||||
@@ -1783,23 +1666,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.6",
|
||||
"signal-exit": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/fraction.js": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
|
||||
@@ -1849,27 +1715,6 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
@@ -1935,16 +1780,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
@@ -1968,35 +1803,13 @@
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/jackspeak": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "1.21.7",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
@@ -2099,32 +1912,6 @@
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -2209,23 +1996,6 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/package-json-from-dist": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0"
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
@@ -2233,30 +2003,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/path-scurry/node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -2317,6 +2063,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -2486,6 +2233,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -2498,6 +2246,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -2517,12 +2266,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.30.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.2.tgz",
|
||||
"integrity": "sha512-H2Bm38Zu1bm8KUE5NVWRMzuIyAV8p/JrOaBJAwVmp37AXG72+CZJlEBw6pdn9i5TBgLMhNDgijS4ZlblpHyWTA==",
|
||||
"version": "6.30.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz",
|
||||
"integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.23.1"
|
||||
"@remix-run/router": "1.23.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
@@ -2532,13 +2281,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.30.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.2.tgz",
|
||||
"integrity": "sha512-l2OwHn3UUnEVUqc6/1VMmR1cvZryZ3j3NzapC2eUXO1dB0sYp5mvwdjiXhpUbRb21eFow3qSxpP8Yv6oAU824Q==",
|
||||
"version": "6.30.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz",
|
||||
"integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.23.1",
|
||||
"react-router": "6.30.2"
|
||||
"@remix-run/router": "1.23.2",
|
||||
"react-router": "6.30.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
@@ -2688,42 +2437,6 @@
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
||||
@@ -2796,123 +2509,19 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"eastasianwidth": "^0.2.0",
|
||||
"emoji-regex": "^9.2.2",
|
||||
"strip-ansi": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width-cjs": {
|
||||
"name": "string-width",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width-cjs/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width-cjs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string-width-cjs/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
|
||||
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi-cjs": {
|
||||
"name": "strip-ansi",
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase": {
|
||||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||
"integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
|
||||
"version": "3.35.1",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
|
||||
"integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"commander": "^4.0.0",
|
||||
"glob": "^10.3.10",
|
||||
"lines-and-columns": "^1.1.6",
|
||||
"mz": "^2.7.0",
|
||||
"pirates": "^4.0.1",
|
||||
"tinyglobby": "^0.2.11",
|
||||
"ts-interface-checker": "^0.1.9"
|
||||
},
|
||||
"bin": {
|
||||
@@ -2997,6 +2606,55 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@@ -3082,6 +2740,7 @@
|
||||
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
@@ -3136,120 +2795,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"node-which": "bin/node-which"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.1.0",
|
||||
"string-width": "^5.0.1",
|
||||
"strip-ansi": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs": {
|
||||
"name": "wrap-ansi",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.30.2",
|
||||
"react-router-dom": "^6.30.3",
|
||||
"socket.io-client": "^4.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1039,12 +1039,25 @@ function App() {
|
||||
record: RequestRecord,
|
||||
options?: {
|
||||
browseOnly?: boolean;
|
||||
manualApproval?: boolean;
|
||||
}
|
||||
) => {
|
||||
if (!requestRoleIsAdmin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options?.manualApproval) {
|
||||
try {
|
||||
await fulfilSidebarRequest(requestId, undefined, undefined, true);
|
||||
await refreshActivitySnapshot();
|
||||
showToast('Request approved', 'success');
|
||||
await fetchStatus();
|
||||
} catch (error) {
|
||||
showToast(getErrorMessage(error, 'Failed to approve request'), 'error');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldBrowse = Boolean(options?.browseOnly) || record.request_level === 'book';
|
||||
|
||||
if (!shouldBrowse && record.request_level === 'release') {
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
releaseLanguageMatchesFilter,
|
||||
buildLanguageNormalizer,
|
||||
} from '../utils/languageFilters';
|
||||
import { getReleaseFormats } from '../utils/releaseFormats';
|
||||
|
||||
// Module-level cache for release search results
|
||||
// Key format: `${provider}:${provider_id}:${source}:${contentType}`
|
||||
@@ -266,9 +267,7 @@ function getTitleMatchScore(title: string, titleCandidate: string): number {
|
||||
|
||||
if (normalizedTitle.startsWith(titleCandidate)) {
|
||||
score += 6000;
|
||||
}
|
||||
|
||||
if (normalizedTitle.includes(titleCandidate)) {
|
||||
} else if (normalizedTitle.includes(titleCandidate)) {
|
||||
score += 3000;
|
||||
}
|
||||
|
||||
@@ -1247,16 +1246,16 @@ export const ReleaseModal = ({
|
||||
const availableFormats = useMemo(() => {
|
||||
const releases = releasesBySource[activeTab]?.releases || [];
|
||||
const formats = new Set<string>();
|
||||
const effectiveLower = effectiveFormats.map((f) => f.toLowerCase());
|
||||
const effectiveLower = new Set(effectiveFormats.map((f) => f.toLowerCase()));
|
||||
|
||||
releases.forEach((r) => {
|
||||
if (r.format) {
|
||||
const fmt = r.format.toLowerCase();
|
||||
const releaseFormats = getReleaseFormats(r);
|
||||
releaseFormats.forEach((fmt) => {
|
||||
// Only include formats that are in the supported list
|
||||
if (effectiveLower.includes(fmt)) {
|
||||
if (effectiveLower.has(fmt)) {
|
||||
formats.add(fmt);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return Array.from(formats).sort();
|
||||
}, [releasesBySource, activeTab, effectiveFormats]);
|
||||
@@ -1390,22 +1389,23 @@ export const ReleaseModal = ({
|
||||
// Filter and sort releases based on settings and user selection
|
||||
const filteredReleases = useMemo(() => {
|
||||
const releases = releasesBySource[activeTab]?.releases || [];
|
||||
const effectiveLower = effectiveFormats.map((f) => f.toLowerCase());
|
||||
const effectiveLower = new Set(effectiveFormats.map((f) => f.toLowerCase()));
|
||||
const supportsIndexerFilter = columnConfig.supported_filters?.includes('indexer');
|
||||
const selectedFormat = formatFilter.toLowerCase();
|
||||
|
||||
// First, filter
|
||||
let filtered = releases.filter((r) => {
|
||||
// Format filtering
|
||||
const fmt = r.format?.toLowerCase();
|
||||
const releaseFormats = getReleaseFormats(r);
|
||||
|
||||
if (formatFilter) {
|
||||
// User selected a specific format - must match exactly
|
||||
if (!fmt || fmt !== formatFilter.toLowerCase()) return false;
|
||||
} else if (fmt) {
|
||||
// No specific filter - show only supported formats
|
||||
if (!effectiveLower.includes(fmt)) return false;
|
||||
// User selected a specific format - match if any format on the release matches
|
||||
if (!releaseFormats.includes(selectedFormat)) return false;
|
||||
} else if (releaseFormats.length > 0) {
|
||||
// No specific filter - show only releases that include at least one supported format
|
||||
if (!releaseFormats.some((fmt) => effectiveLower.has(fmt))) return false;
|
||||
}
|
||||
// Releases with no format pass through when no filter is set (show all)
|
||||
// Releases with no format info pass through when no filter is set (show all)
|
||||
|
||||
// Language filtering - use r.language when provided by enriched indexers
|
||||
// Releases with no language (null/undefined) always pass
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
|
||||
interface RequestApproveOptions {
|
||||
browseOnly?: boolean;
|
||||
manualApproval?: boolean;
|
||||
}
|
||||
|
||||
type RequestApproveHandler = (
|
||||
@@ -431,6 +432,7 @@ export const ActivityCard = ({
|
||||
? 'Browse Releases To Retry'
|
||||
: 'Browse Releases To Approve'
|
||||
: 'Approve Attached File';
|
||||
const canMarkAsApprovedWithoutRelease = requiresBrowseBeforeApprove && !hasAttachedRelease;
|
||||
|
||||
const provider = toOptionalText(bookData.provider)?.toLowerCase();
|
||||
const providerId = toOptionalText(bookData.provider_id);
|
||||
@@ -467,6 +469,19 @@ export const ActivityCard = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleReviewManualApproval = async () => {
|
||||
if (!reviewRecord || !reviewApproveHandler || isReviewSubmitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsReviewSubmitting(true);
|
||||
try {
|
||||
await reviewApproveHandler(reviewRecord.id, reviewRecord, { manualApproval: true });
|
||||
} finally {
|
||||
setIsReviewSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const canShowInlineReview = Boolean(isRequestDetailsOpen && reviewRecord && reviewApproveHandler);
|
||||
const rejectConfirmHandler = onRequestRejectConfirm || onRequestReject;
|
||||
const canShowInlineReject = Boolean(
|
||||
@@ -704,6 +719,16 @@ export const ActivityCard = ({
|
||||
>
|
||||
{isReviewSubmitting ? 'Working...' : approveLabel}
|
||||
</button>
|
||||
{canMarkAsApprovedWithoutRelease && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleReviewManualApproval}
|
||||
disabled={isReviewSubmitting}
|
||||
className="px-2.5 py-1.5 rounded-md text-xs border border-[var(--border-muted)] hover:bg-[var(--hover-surface)] transition-colors disabled:opacity-50"
|
||||
>
|
||||
{isReviewSubmitting ? 'Working...' : 'Manually Mark as Approved'}
|
||||
</button>
|
||||
)}
|
||||
{canBrowseAlternatives && hasAttachedRelease && (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -30,6 +30,7 @@ interface ActivitySidebarProps {
|
||||
record: RequestRecord,
|
||||
options?: {
|
||||
browseOnly?: boolean;
|
||||
manualApproval?: boolean;
|
||||
}
|
||||
) => Promise<void> | void;
|
||||
onRequestReject?: (requestId: number, adminNote?: string) => Promise<void> | void;
|
||||
|
||||
@@ -260,9 +260,9 @@ export const RequestPolicyGrid = ({
|
||||
|
||||
if (!isConfigurable) {
|
||||
return (
|
||||
<div key={key} className="flex items-center min-h-[36px]">
|
||||
<div key={key} className="flex items-center justify-center min-h-[36px]">
|
||||
{mobileLabel}
|
||||
<span className="text-sm opacity-50">
|
||||
<span className="text-xs opacity-40">
|
||||
{REQUEST_POLICY_MODE_LABELS[effectiveMode]}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -154,21 +154,24 @@ export function useAuth(options: UseAuthOptions = {}): UseAuthReturn {
|
||||
window.location.href = logout_url;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Reload auth settings after session clear so /login has current auth-mode UI config.
|
||||
applyAuthResponse(await checkAuth());
|
||||
} catch (error) {
|
||||
console.error('Post-logout auth refresh failed:', error);
|
||||
setIsAuthenticated(false);
|
||||
setIsAdmin(false);
|
||||
setUsername(null);
|
||||
setDisplayName(null);
|
||||
}
|
||||
refreshSocketSession();
|
||||
setIsAuthenticated(false);
|
||||
setIsAdmin(false);
|
||||
setUsername(null);
|
||||
setDisplayName(null);
|
||||
setOidcButtonLabel(null);
|
||||
setHideLocalAuth(false);
|
||||
setOidcAutoRedirect(false);
|
||||
onLogoutSuccess?.();
|
||||
navigate('/login', { replace: true });
|
||||
} catch (error) {
|
||||
console.error('Logout failed:', error);
|
||||
showToast?.('Logout failed', 'error');
|
||||
}
|
||||
}, [navigate, onLogoutSuccess, refreshSocketSession, showToast]);
|
||||
}, [navigate, onLogoutSuccess, refreshSocketSession, showToast, applyAuthResponse]);
|
||||
|
||||
return {
|
||||
isAuthenticated,
|
||||
|
||||
@@ -32,7 +32,8 @@ export interface UseRequestsReturn {
|
||||
fulfilRequest: (
|
||||
id: number,
|
||||
releaseData?: Record<string, unknown>,
|
||||
adminNote?: string
|
||||
adminNote?: string,
|
||||
manualApproval?: boolean
|
||||
) => Promise<void>;
|
||||
rejectRequest: (id: number, adminNote?: string) => Promise<void>;
|
||||
}
|
||||
@@ -217,7 +218,12 @@ export const useRequests = ({
|
||||
}, []);
|
||||
|
||||
const fulfilRequest = useCallback(
|
||||
async (id: number, releaseData?: Record<string, unknown>, adminNote?: string) => {
|
||||
async (
|
||||
id: number,
|
||||
releaseData?: Record<string, unknown>,
|
||||
adminNote?: string,
|
||||
manualApproval?: boolean
|
||||
) => {
|
||||
if (!isAdmin) {
|
||||
throw new Error('Admin access required');
|
||||
}
|
||||
@@ -232,6 +238,7 @@ export const useRequests = ({
|
||||
const updated = await fulfilAdminRequest(id, {
|
||||
release_data: releaseData,
|
||||
admin_note: adminNote,
|
||||
manual_approval: manualApproval,
|
||||
});
|
||||
setRequests((prev) => upsertRequestRecord(prev, updated));
|
||||
setError(null);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useRef } from 'react';
|
||||
import { useState, useCallback, useRef, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Book, AppConfig, AdvancedFilterState, ContentType } from '../types';
|
||||
import { searchBooks, searchMetadata, AuthenticationError } from '../services/api';
|
||||
@@ -78,6 +78,24 @@ export function useSearch(options: UseSearchOptions): UseSearchReturn {
|
||||
sort: string;
|
||||
fieldValues: SearchFieldValues;
|
||||
} | null>(null);
|
||||
const previousContentTypeRef = useRef<ContentType>(contentType);
|
||||
|
||||
// Switching media type starts a new search session.
|
||||
useEffect(() => {
|
||||
if (previousContentTypeRef.current === contentType) {
|
||||
return;
|
||||
}
|
||||
|
||||
previousContentTypeRef.current = contentType;
|
||||
setBooks([]);
|
||||
setLastSearchQuery('');
|
||||
setSearchFieldValues({});
|
||||
setHasMore(false);
|
||||
setTotalFound(0);
|
||||
setCurrentPage(1);
|
||||
lastSearchParamsRef.current = null;
|
||||
onSearchReset?.();
|
||||
}, [contentType, onSearchReset]);
|
||||
|
||||
const updateAdvancedFilters = useCallback((updates: Partial<AdvancedFilterState>) => {
|
||||
setAdvancedFilters(prev => ({ ...prev, ...updates }));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { useState, useCallback, useEffect, useRef } from 'react';
|
||||
import { getSettings, updateSettings, executeSettingsAction } from '../services/api';
|
||||
import {
|
||||
SettingsTab,
|
||||
@@ -12,12 +12,22 @@ import {
|
||||
setThemePreference,
|
||||
THEME_FIELD,
|
||||
} from '../utils/themePreference';
|
||||
import {
|
||||
cloneSettingsValues,
|
||||
mergeFetchedSettingsWithDirtyValues,
|
||||
type SettingsValues,
|
||||
} from '../utils/settingsValues';
|
||||
|
||||
type ValueBearingField = Exclude<
|
||||
SettingsField,
|
||||
{ type: 'ActionButton' } | { type: 'HeadingField' } | { type: 'CustomComponentField' }
|
||||
>;
|
||||
|
||||
interface FetchSettingsOptions {
|
||||
silent?: boolean;
|
||||
preserveDirtyValues?: boolean;
|
||||
}
|
||||
|
||||
// Extract value from a field based on its type
|
||||
function getFieldValue(field: SettingsField): unknown {
|
||||
// These field types have no value property
|
||||
@@ -88,11 +98,22 @@ export function useSettings(): UseSettingsReturn {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [selectedTab, setSelectedTab] = useState<string | null>(null);
|
||||
const [values, setValues] = useState<Record<string, Record<string, unknown>>>({});
|
||||
const [originalValues, setOriginalValues] = useState<Record<string, Record<string, unknown>>>({});
|
||||
const [values, setValues] = useState<SettingsValues>({});
|
||||
const [originalValues, setOriginalValues] = useState<SettingsValues>({});
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const valuesRef = useRef<SettingsValues>({});
|
||||
const originalValuesRef = useRef<SettingsValues>({});
|
||||
|
||||
const fetchSettings = useCallback(async (silent = false) => {
|
||||
useEffect(() => {
|
||||
valuesRef.current = values;
|
||||
}, [values]);
|
||||
|
||||
useEffect(() => {
|
||||
originalValuesRef.current = originalValues;
|
||||
}, [originalValues]);
|
||||
|
||||
const fetchSettings = useCallback(async (options: FetchSettingsOptions = {}) => {
|
||||
const { silent = false, preserveDirtyValues = false } = options;
|
||||
if (!silent) {
|
||||
setIsLoading(true);
|
||||
}
|
||||
@@ -114,7 +135,7 @@ export function useSettings(): UseSettingsReturn {
|
||||
setGroups(response.groups || []);
|
||||
|
||||
// Initialize values from fetched data
|
||||
const initialValues: Record<string, Record<string, unknown>> = {};
|
||||
const initialValues: SettingsValues = {};
|
||||
tabsWithTheme.forEach((tab) => {
|
||||
initialValues[tab.name] = {};
|
||||
getValueBearingFields(tab.fields).forEach((field) => {
|
||||
@@ -127,8 +148,12 @@ export function useSettings(): UseSettingsReturn {
|
||||
});
|
||||
});
|
||||
|
||||
setValues(initialValues);
|
||||
setOriginalValues(JSON.parse(JSON.stringify(initialValues)));
|
||||
const nextValues = preserveDirtyValues
|
||||
? mergeFetchedSettingsWithDirtyValues(initialValues, valuesRef.current, originalValuesRef.current)
|
||||
: initialValues;
|
||||
|
||||
setValues(nextValues);
|
||||
setOriginalValues(cloneSettingsValues(initialValues));
|
||||
|
||||
// Select first tab by default if none selected
|
||||
if (tabsWithTheme.length > 0) {
|
||||
@@ -231,7 +256,7 @@ export function useSettings(): UseSettingsReturn {
|
||||
if (result.success) {
|
||||
// Refetch all settings silently to pick up any backend-triggered changes
|
||||
// (e.g., enabling a metadata provider auto-updates METADATA_PROVIDER)
|
||||
await fetchSettings(true);
|
||||
await fetchSettings({ silent: true });
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -259,7 +284,7 @@ export function useSettings(): UseSettingsReturn {
|
||||
// Re-fetch settings after successful action to pick up updated options
|
||||
// (e.g., BookLore "Test Connection" refreshes library/path lists)
|
||||
if (result.success) {
|
||||
fetchSettings(true);
|
||||
await fetchSettings({ silent: true, preserveDirtyValues: true });
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -287,6 +312,6 @@ export function useSettings(): UseSettingsReturn {
|
||||
saveTab,
|
||||
executeAction,
|
||||
isSaving,
|
||||
refetch: fetchSettings,
|
||||
refetch: () => fetchSettings(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface RequestListParams {
|
||||
export interface FulfilAdminRequestBody {
|
||||
release_data?: Record<string, unknown>;
|
||||
admin_note?: string;
|
||||
manual_approval?: boolean;
|
||||
}
|
||||
|
||||
export interface RejectAdminRequestBody {
|
||||
@@ -45,10 +46,17 @@ export const buildAdminRequestActionUrl = (
|
||||
export const buildFulfilAdminRequestBody = (
|
||||
body: FulfilAdminRequestBody = {}
|
||||
): FulfilAdminRequestBody => {
|
||||
return {
|
||||
release_data: body.release_data,
|
||||
admin_note: body.admin_note,
|
||||
};
|
||||
const payload: FulfilAdminRequestBody = {};
|
||||
if (body.release_data !== undefined) {
|
||||
payload.release_data = body.release_data;
|
||||
}
|
||||
if (body.admin_note !== undefined) {
|
||||
payload.admin_note = body.admin_note;
|
||||
}
|
||||
if (body.manual_approval !== undefined) {
|
||||
payload.manual_approval = body.manual_approval;
|
||||
}
|
||||
return payload;
|
||||
};
|
||||
|
||||
export const buildRejectAdminRequestBody = (
|
||||
|
||||
@@ -36,6 +36,18 @@ describe('admin request API client functions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('builds manual-approval fulfil payload without release data', () => {
|
||||
const body = buildFulfilAdminRequestBody({
|
||||
manual_approval: true,
|
||||
admin_note: 'Handled manually',
|
||||
});
|
||||
|
||||
assert.deepEqual(body, {
|
||||
manual_approval: true,
|
||||
admin_note: 'Handled manually',
|
||||
});
|
||||
});
|
||||
|
||||
it('builds reject endpoint URL and payload shape', () => {
|
||||
const url = buildAdminRequestActionUrl('/api/admin/requests', 51, 'reject');
|
||||
const body = buildRejectAdminRequestBody({
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { getReleaseFormats } from '../utils/releaseFormats.js';
|
||||
import type { Release } from '../types';
|
||||
|
||||
function buildRelease(overrides: Partial<Release>): Release {
|
||||
return {
|
||||
source: 'prowlarr',
|
||||
source_id: 'release-1',
|
||||
title: 'Test Release',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe('releaseFormats.getReleaseFormats', () => {
|
||||
it('returns primary and extra formats in order, normalized and deduplicated', () => {
|
||||
const release = buildRelease({
|
||||
format: 'AZW3',
|
||||
extra: { formats: ['MOBI', 'EPUB', 'azw3', ' mobi '] },
|
||||
});
|
||||
|
||||
assert.deepEqual(getReleaseFormats(release), ['azw3', 'mobi', 'epub']);
|
||||
});
|
||||
|
||||
it('uses extra formats when primary format is missing', () => {
|
||||
const release = buildRelease({
|
||||
extra: { formats: ['EPUB', 'MOBI'] },
|
||||
});
|
||||
|
||||
assert.deepEqual(getReleaseFormats(release), ['epub', 'mobi']);
|
||||
});
|
||||
|
||||
it('supports legacy string value in extra.formats', () => {
|
||||
const release = buildRelease({
|
||||
extra: { formats: 'PDF' },
|
||||
});
|
||||
|
||||
assert.deepEqual(getReleaseFormats(release), ['pdf']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import * as assert from 'node:assert/strict';
|
||||
import { describe, it } from 'node:test';
|
||||
import { mergeFetchedSettingsWithDirtyValues } from '../utils/settingsValues.js';
|
||||
|
||||
describe('mergeFetchedSettingsWithDirtyValues', () => {
|
||||
it('preserves unsaved dirty values while applying fresh fetched values', () => {
|
||||
const fetchedValues = {
|
||||
general: {
|
||||
apiKey: 'saved-key',
|
||||
endpoint: 'https://saved.example',
|
||||
},
|
||||
};
|
||||
|
||||
const currentValues = {
|
||||
general: {
|
||||
apiKey: 'unsaved-key',
|
||||
endpoint: 'https://saved.example',
|
||||
},
|
||||
};
|
||||
|
||||
const originalValues = {
|
||||
general: {
|
||||
apiKey: 'saved-key',
|
||||
endpoint: 'https://saved.example',
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepEqual(
|
||||
mergeFetchedSettingsWithDirtyValues(fetchedValues, currentValues, originalValues),
|
||||
{
|
||||
general: {
|
||||
apiKey: 'unsaved-key',
|
||||
endpoint: 'https://saved.example',
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('does not preserve values that are not dirty and ignores keys removed by backend', () => {
|
||||
const fetchedValues = {
|
||||
provider: {
|
||||
host: 'new-host',
|
||||
enabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
const currentValues = {
|
||||
provider: {
|
||||
host: 'old-host',
|
||||
enabled: false,
|
||||
removedField: 'local-only',
|
||||
},
|
||||
};
|
||||
|
||||
const originalValues = {
|
||||
provider: {
|
||||
host: 'old-host',
|
||||
enabled: false,
|
||||
removedField: 'local-only',
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepEqual(
|
||||
mergeFetchedSettingsWithDirtyValues(fetchedValues, currentValues, originalValues),
|
||||
{
|
||||
provider: {
|
||||
host: 'new-host',
|
||||
enabled: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Release } from '../types';
|
||||
|
||||
function normalizeFormatValue(value: unknown): string | null {
|
||||
if (typeof value !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalized = value.trim().toLowerCase();
|
||||
return normalized.length > 0 ? normalized : null;
|
||||
}
|
||||
|
||||
export function getReleaseFormats(release: Release): string[] {
|
||||
const formats: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
const addFormat = (value: unknown): void => {
|
||||
const normalized = normalizeFormatValue(value);
|
||||
if (!normalized || seen.has(normalized)) {
|
||||
return;
|
||||
}
|
||||
seen.add(normalized);
|
||||
formats.push(normalized);
|
||||
};
|
||||
|
||||
addFormat(release.format);
|
||||
|
||||
const extraFormats = (release.extra as Record<string, unknown> | undefined)?.formats;
|
||||
if (Array.isArray(extraFormats)) {
|
||||
extraFormats.forEach(addFormat);
|
||||
} else {
|
||||
addFormat(extraFormats);
|
||||
}
|
||||
|
||||
return formats;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
export type SettingsValues = Record<string, Record<string, unknown>>;
|
||||
|
||||
export function cloneSettingsValues(values: SettingsValues): SettingsValues {
|
||||
return JSON.parse(JSON.stringify(values)) as SettingsValues;
|
||||
}
|
||||
|
||||
export function mergeFetchedSettingsWithDirtyValues(
|
||||
fetchedValues: SettingsValues,
|
||||
currentValues: SettingsValues,
|
||||
originalValues: SettingsValues
|
||||
): SettingsValues {
|
||||
const mergedValues: SettingsValues = {};
|
||||
|
||||
for (const [tabName, fetchedTabValues] of Object.entries(fetchedValues)) {
|
||||
mergedValues[tabName] = { ...fetchedTabValues };
|
||||
const currentTabValues = currentValues[tabName] ?? {};
|
||||
const originalTabValues = originalValues[tabName] ?? {};
|
||||
|
||||
for (const [key, currentValue] of Object.entries(currentTabValues)) {
|
||||
if (!(key in fetchedTabValues)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const originalValue = originalTabValues[key];
|
||||
if (JSON.stringify(currentValue) !== JSON.stringify(originalValue)) {
|
||||
mergedValues[tabName][key] = currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mergedValues;
|
||||
}
|
||||
@@ -9,10 +9,5 @@
|
||||
"types": ["node"],
|
||||
"allowImportingTsExtensions": false
|
||||
},
|
||||
"include": [
|
||||
"src/tests/**/*.node.test.ts",
|
||||
"src/hooks/requestPolicyCore.ts",
|
||||
"src/utils/requestPolicyUi.ts",
|
||||
"src/types/index.ts"
|
||||
]
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user