diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index b4da534281..6eb164ba42 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -115,7 +115,7 @@
"postcss-preset-mantine": "^1.18.0",
"postcss-simple-vars": "^7.0.1",
"puppeteer": "^24.25.0",
- "tsx": "^4.19.4",
+ "tsx": "^4.21.0",
"typescript": "^5.9.2",
"typescript-eslint": "^8.44.1",
"vite": "^7.1.7",
@@ -476,6 +476,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=20.19.0"
},
@@ -516,6 +517,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=20.19.0"
}
@@ -578,6 +580,7 @@
"resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-2.7.0.tgz",
"integrity": "sha512-dJ9pCWXVJxh6uSJP4sKuJP4v67+6Vlmw4WqJcv+CKJSUPdX9LhOSTIgTjwKLZ5zXo0c3DihNvrUupovb/DrhgQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@embedpdf/engines": "2.7.0",
"@embedpdf/models": "2.7.0"
@@ -673,6 +676,7 @@
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-annotation/-/plugin-annotation-2.7.0.tgz",
"integrity": "sha512-bkn9+91XfcFoKgwZ0kiJLbnvWNyrorhcbX5grsvUw2gJ8mL0RtwHSnCjZVT3WOPleQVwnNkBZUHefJhNT+LEKw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@embedpdf/models": "2.7.0",
"@embedpdf/utils": "2.7.0"
@@ -762,6 +766,7 @@
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-2.7.0.tgz",
"integrity": "sha512-k2c5M2Nwey+j6EtZyf5Sw+cuyNT4MTWdqPQGR9NbmZUiNnkSrg/TmPWZCyaXZKGRjLmoJocc0qRdyaZnaaTpqw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@embedpdf/models": "2.7.0"
},
@@ -779,6 +784,7 @@
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-2.7.0.tgz",
"integrity": "sha512-IfJiugr2k9VD8/gryMb22wC5yk4EQwSS3/Co0EdOhzkmkGSgUHA/KcG83WBu8wPEtj5Gwy473xe41fYKsGMlsA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@embedpdf/models": "2.7.0"
},
@@ -854,6 +860,7 @@
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-2.7.0.tgz",
"integrity": "sha512-qJcBxl2Kgqbw/Yb4qiX3qNsBKmzI8ijAKix3PoYL+nlhX6iFbcCkUbJgF0rPCBbhIy59Bpp7eJL+RyY5DhQvUg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@embedpdf/models": "2.7.0"
},
@@ -888,6 +895,7 @@
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-2.7.0.tgz",
"integrity": "sha512-uEs5XdHZ3XqH3OWnM8E2eHen+7+MxK9SrlBnfM8ZcPkzHR9n7hT/Aqy05BiLKxKem585HvtbRgFzNQZqmNIGHw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@embedpdf/models": "2.7.0"
},
@@ -923,6 +931,7 @@
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-2.7.0.tgz",
"integrity": "sha512-MhTUHZ5jBh1jQU66xrtkx2jEtcreCfHy4zpmMY7iCoZtWUxrML+zf4jYNrR/ZP93O4i5HNBSnJNTG+RmRJ5KPw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@embedpdf/models": "2.7.0",
"@embedpdf/utils": "2.7.0"
@@ -997,6 +1006,7 @@
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-2.7.0.tgz",
"integrity": "sha512-nVDoU86CgHme7f2r7OFhziqHz1Yg8vdE2K+bXzRCmtZaubH+qVo5C+77at9brYCSinA67znQn1yy6zbfxs4FwA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@embedpdf/models": "2.7.0"
},
@@ -1099,6 +1109,7 @@
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -1142,6 +1153,7 @@
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -2000,6 +2012,7 @@
"resolved": "https://registry.npmjs.org/@mantine/core/-/core-8.3.15.tgz",
"integrity": "sha512-wBn/GogB4x7a2Uj7Ztt3amRaApjED+9XqfE4wyCLh88R7KV55k9vnTdCx+irI/GLOOu9tXNUGm3a4t5sTajwkQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@floating-ui/react": "^0.27.16",
"clsx": "^2.1.1",
@@ -2050,6 +2063,7 @@
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-8.3.15.tgz",
"integrity": "sha512-AUSnpUlzttHzJht3CJ1YWi16iy6NWRwtyWO5RLGHHsmiW05DyG0qOPKF8+R5dLHuOCnl3XOu4roI2Y1ku9U04Q==",
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"react": "^18.x || ^19.x"
}
@@ -2126,6 +2140,7 @@
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.8.tgz",
"integrity": "sha512-QKd1RhDXE1hf2sQDNayA9ic9jGkEgvZOf0tTkJxlBPG8ns8aS4rS8WwYURw2x5y3739p0HauUXX9WbH7UufFLw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.28.6",
"@mui/core-downloads-tracker": "^7.3.8",
@@ -2573,6 +2588,7 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"license": "Apache-2.0",
+ "peer": true,
"engines": {
"node": ">=8.0.0"
}
@@ -3488,6 +3504,7 @@
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-7.9.0.tgz",
"integrity": "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12.16"
}
@@ -3577,7 +3594,6 @@
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz",
"integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==",
"license": "MIT",
- "peer": true,
"peerDependencies": {
"acorn": "^8.9.0"
}
@@ -4369,6 +4385,7 @@
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -4962,6 +4979,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -4972,6 +4990,7 @@
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -5052,6 +5071,7 @@
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.56.1",
"@typescript-eslint/types": "8.56.1",
@@ -5501,7 +5521,6 @@
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.29.tgz",
"integrity": "sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@vue/shared": "3.5.29"
}
@@ -5511,7 +5530,6 @@
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.29.tgz",
"integrity": "sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@vue/reactivity": "3.5.29",
"@vue/shared": "3.5.29"
@@ -5522,7 +5540,6 @@
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.29.tgz",
"integrity": "sha512-AHvvJEtcY9tw/uk+s/YRLSlxxQnqnAkjqvK25ZiM4CllCZWzElRAoQnCM42m9AHRLNJ6oe2kC5DCgD4AUdlvXg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@vue/reactivity": "3.5.29",
"@vue/runtime-core": "3.5.29",
@@ -5535,7 +5552,6 @@
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.29.tgz",
"integrity": "sha512-G/1k6WK5MusLlbxSE2YTcqAAezS+VuwHhOvLx2KnQU7G2zCH6KIb+5Wyt6UjMq7a3qPzNEjJXs1hvAxDclQH+g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@vue/compiler-ssr": "3.5.29",
"@vue/shared": "3.5.29"
@@ -5562,6 +5578,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5813,7 +5830,6 @@
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
"license": "Apache-2.0",
- "peer": true,
"engines": {
"node": ">= 0.4"
}
@@ -6100,6 +6116,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -7011,6 +7028,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
+ "peer": true,
"engines": {
"node": ">=12"
}
@@ -7473,15 +7491,15 @@
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz",
"integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/devtools-protocol": {
"version": "0.0.1566079",
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1566079.tgz",
"integrity": "sha512-MJfAEA1UfVhSs7fbSQOG4czavUp1ajfg6prlAN0+cmfa2zNjaIbvq8VneP7do1WAQQIvgNJWSMeP6UyI90gIlQ==",
"dev": true,
- "license": "BSD-3-Clause"
+ "license": "BSD-3-Clause",
+ "peer": true
},
"node_modules/dezalgo": {
"version": "1.0.4",
@@ -7869,6 +7887,7 @@
"integrity": "sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.2",
@@ -7978,8 +7997,7 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/espree": {
"version": "11.1.1",
@@ -8044,7 +8062,6 @@
"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.3.tgz",
"integrity": "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
}
@@ -8866,6 +8883,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.28.4"
},
@@ -9146,7 +9164,6 @@
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/estree": "^1.0.6"
}
@@ -9322,6 +9339,7 @@
"integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@acemir/cssom": "^0.9.28",
"@asamuzakjp/dom-selector": "^6.7.6",
@@ -9883,8 +9901,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/locate-path": {
"version": "6.0.0",
@@ -10904,6 +10921,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -11164,6 +11182,7 @@
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.354.0.tgz",
"integrity": "sha512-qrpToz7mN1PmEfo+Ob4Z8euX4z2p17LA0EAtFeyod3IVnlwnu+Ybea/oxVsPiq5YAPo+p5z73FcjF2yEJ7oZnA==",
"license": "SEE LICENSE IN LICENSE",
+ "peer": true,
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/api-logs": "^0.208.0",
@@ -11185,6 +11204,7 @@
"resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz",
"integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
@@ -11559,6 +11579,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -11568,6 +11589,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -11659,7 +11681,8 @@
"version": "19.2.4",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz",
"integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/react-number-format": {
"version": "5.4.4",
@@ -11676,6 +11699,7 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@@ -12057,7 +12081,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/redux-thunk": {
"version": "3.1.0",
@@ -12907,7 +12932,6 @@
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz",
"integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==",
"license": "Apache-2.0",
- "peer": true,
"engines": {
"node": ">= 0.4"
}
@@ -13235,6 +13259,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -13428,6 +13453,7 @@
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
@@ -13495,6 +13521,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"devOptional": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -13745,6 +13772,7 @@
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -13919,6 +13947,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -13932,6 +13961,7 @@
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/chai": "^5.2.2",
"@vitest/expect": "3.2.4",
@@ -14442,8 +14472,7 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/zod": {
"version": "3.25.76",
diff --git a/frontend/package.json b/frontend/package.json
index b78dafa0b7..3b13d2b173 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -40,6 +40,7 @@
"@mantine/hooks": "^8.3.1",
"@mui/icons-material": "^7.3.2",
"@mui/material": "^7.3.2",
+ "@posthog/react": "^1.8.2",
"@reactour/tour": "^3.8.0",
"@stripe/react-stripe-js": "^4.0.2",
"@stripe/stripe-js": "^7.9.0",
@@ -63,7 +64,6 @@
"license-report": "^6.8.0",
"pdfjs-dist": "^5.4.149",
"peerjs": "^1.5.5",
- "@posthog/react": "^1.8.2",
"posthog-js": "^1.268.0",
"qrcode.react": "^4.2.0",
"react": "^19.1.1",
@@ -174,8 +174,8 @@
"postcss-preset-mantine": "^1.18.0",
"postcss-simple-vars": "^7.0.1",
"puppeteer": "^24.25.0",
+ "tsx": "^4.21.0",
"typescript": "^5.9.2",
- "tsx": "^4.19.4",
"typescript-eslint": "^8.44.1",
"vite": "^7.1.7",
"vite-plugin-static-copy": "^3.1.4",
diff --git a/frontend/public/locales/en-GB/translation.toml b/frontend/public/locales/en-GB/translation.toml
index 810c52d03d..66971ce304 100644
--- a/frontend/public/locales/en-GB/translation.toml
+++ b/frontend/public/locales/en-GB/translation.toml
@@ -4475,6 +4475,7 @@ exitRedaction = "Exit Redaction Mode"
save = "Save"
downloadAll = "Download All"
saveAll = "Save All"
+saveAs = "Save As"
[textAlign]
left = "Left"
diff --git a/frontend/src/core/components/shared/RightRail.tsx b/frontend/src/core/components/shared/RightRail.tsx
index 11ecbb4a90..8001b17f73 100644
--- a/frontend/src/core/components/shared/RightRail.tsx
+++ b/frontend/src/core/components/shared/RightRail.tsx
@@ -134,68 +134,71 @@ export default function RightRail() {
[actions, allButtonsDisabled, disableForFullscreen, tooltipPosition, tooltipOffset]
);
- const handleExportAll = useCallback(async () => {
- if (currentView === 'viewer') {
- const buffer = await viewerContext?.exportActions?.saveAsCopy?.();
- if (!buffer) return;
- const fileToExport = selectedFiles.length > 0 ? selectedFiles[0] : activeFiles[0];
- if (!fileToExport) return;
- const stub = isStirlingFile(fileToExport) ? selectors.getStirlingFileStub(fileToExport.fileId) : undefined;
- try {
- const result = await downloadFile({
- data: new Blob([buffer], { type: 'application/pdf' }),
- filename: fileToExport.name,
- localPath: stub?.localFilePath,
- });
- if (!result.cancelled && stub && result.savedPath) {
- fileActions.updateStirlingFileStub(stub.id, {
- localFilePath: stub.localFilePath ?? result.savedPath,
- isDirty: false,
- });
- }
- } catch (error) {
- console.error('[RightRail] Failed to export viewer file:', error);
- }
- return;
- }
-
- if (currentView === 'pageEditor') {
- pageEditorFunctions?.onExportAll?.();
- return;
- }
-
- const filesToExport = selectedFiles.length > 0 ? selectedFiles : activeFiles;
-
- if (filesToExport.length > 0) {
- for (const file of filesToExport) {
- const stub = isStirlingFile(file) ? selectors.getStirlingFileStub(file.fileId) : undefined;
+ const handleExportAll = useCallback(
+ async (forceNewFile = false) => {
+ if (currentView === 'viewer') {
+ const buffer = await viewerContext?.exportActions?.saveAsCopy?.();
+ if (!buffer) return;
+ const fileToExport = selectedFiles.length > 0 ? selectedFiles[0] : activeFiles[0];
+ if (!fileToExport) return;
+ const stub = isStirlingFile(fileToExport) ? selectors.getStirlingFileStub(fileToExport.fileId) : undefined;
try {
const result = await downloadFile({
- data: file,
- filename: file.name,
- localPath: stub?.localFilePath
+ data: new Blob([buffer], { type: 'application/pdf' }),
+ filename: fileToExport.name,
+ localPath: forceNewFile ? undefined : stub?.localFilePath,
});
- if (result.cancelled) continue;
- if (stub && result.savedPath) {
+ if (!forceNewFile && !result.cancelled && stub && result.savedPath) {
fileActions.updateStirlingFileStub(stub.id, {
localFilePath: stub.localFilePath ?? result.savedPath,
- isDirty: false
+ isDirty: false,
});
}
} catch (error) {
- console.error('[RightRail] Failed to export file:', file.name, error);
+ console.error('[RightRail] Failed to export viewer file:', error);
+ }
+ return;
+ }
+
+ if (currentView === 'pageEditor') {
+ pageEditorFunctions?.onExportAll?.();
+ return;
+ }
+
+ const filesToExport = selectedFiles.length > 0 ? selectedFiles : activeFiles;
+
+ if (filesToExport.length > 0) {
+ for (const file of filesToExport) {
+ const stub = isStirlingFile(file) ? selectors.getStirlingFileStub(file.fileId) : undefined;
+ try {
+ const result = await downloadFile({
+ data: file,
+ filename: file.name,
+ localPath: forceNewFile ? undefined : stub?.localFilePath,
+ });
+ if (result.cancelled) continue;
+ if (!forceNewFile && stub && result.savedPath) {
+ fileActions.updateStirlingFileStub(stub.id, {
+ localFilePath: stub.localFilePath ?? result.savedPath,
+ isDirty: false,
+ });
+ }
+ } catch (error) {
+ console.error('[RightRail] Failed to export file:', file.name, error);
+ }
}
}
- }
- }, [
- currentView,
- selectedFiles,
- activeFiles,
- pageEditorFunctions,
- viewerContext,
- selectors,
- fileActions,
- ]);
+ },
+ [
+ currentView,
+ selectedFiles,
+ activeFiles,
+ pageEditorFunctions,
+ viewerContext,
+ selectors,
+ fileActions,
+ ]
+ );
const downloadTooltip = useMemo(() => {
if (currentView === 'pageEditor') {
@@ -264,7 +267,7 @@ export default function RightRail() {
variant="subtle"
radius="md"
className="right-rail-icon"
- onClick={handleExportAll}
+ onClick={() => handleExportAll()}
disabled={
disableForFullscreen ||
(currentView !== 'viewer' && (totalItems === 0 || allButtonsDisabled))
@@ -276,6 +279,24 @@ export default function RightRail() {
tooltipPosition,
tooltipOffset
)}
+ {icons.saveAsIconName &&
+ renderWithTooltip(
+