From ef9bec3334724a01e6c9be6c943468a70d955838 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Mon, 10 Nov 2025 14:46:34 +0100 Subject: [PATCH 01/13] update deps --- frontend/.eslintignore | 2 - frontend/.eslintrc.json | 31 - frontend/eslint.config.mjs | 53 + frontend/package-lock.json | 1826 +++++++---------- frontend/package.json | 41 +- frontend/src/desktop/db.js | 2 +- frontend/src/desktop/workspaceEngine.js | 2 - .../documents/hooks/useBulkDocumentActions.js | 3 +- frontend/src/documents/useInlineRename.js | 2 +- .../useDocumentCorrespondentActions.js | 3 +- .../src/hooks/documents/useDocumentUploads.js | 4 - .../hooks/documents/useFolderTreeActions.js | 3 - .../settings/sections/ApiTokensSection.jsx | 2 +- frontend/src/ui/BreadcrumbTrail.jsx | 6 - frontend/src/utils/ocr.js | 6 +- 15 files changed, 845 insertions(+), 1141 deletions(-) delete mode 100644 frontend/.eslintignore delete mode 100644 frontend/.eslintrc.json create mode 100644 frontend/eslint.config.mjs diff --git a/frontend/.eslintignore b/frontend/.eslintignore deleted file mode 100644 index de4d1f0..0000000 --- a/frontend/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json deleted file mode 100644 index 0b096ce..0000000 --- a/frontend/.eslintrc.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:react-hooks/recommended" - ], - "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, - "ecmaVersion": "latest", - "sourceType": "module" - }, - "settings": { - "react": { - "version": "detect" - } - }, - "rules": { - "no-use-before-define": [ - "error", - { "functions": false, "classes": true, "variables": true } - ], - "react/react-in-jsx-scope": "off", - "react/prop-types": "off" - } -} diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs new file mode 100644 index 0000000..fc2c17b --- /dev/null +++ b/frontend/eslint.config.mjs @@ -0,0 +1,53 @@ +import js from '@eslint/js'; +import pluginReact from 'eslint-plugin-react'; +import pluginReactHooks from 'eslint-plugin-react-hooks'; +import globals from 'globals'; + +const sharedRules = { + ...js.configs.recommended.rules, + ...pluginReact.configs.recommended.rules, + ...pluginReactHooks.configs.recommended.rules, + 'no-use-before-define': [ + 'error', + { functions: false, classes: true, variables: true }, + ], + 'react/react-in-jsx-scope': 'off', + 'react/prop-types': 'off', + 'react-hooks/set-state-in-effect': 'off', + 'react-hooks/refs': 'off', + 'react-hooks/preserve-manual-memoization': 'off', +}; + +const sharedLanguageOptions = { + ecmaVersion: 'latest', + sourceType: 'module', + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + ...globals.browser, + ...globals.node, + }, +}; + +export default [ + { + ignores: ['dist', 'node_modules'], + }, + { + files: ['src/**/*.{js,jsx}', 'tests/**/*.{js,jsx}'], + languageOptions: sharedLanguageOptions, + plugins: { + react: pluginReact, + 'react-hooks': pluginReactHooks, + }, + settings: { + react: { + version: 'detect', + }, + }, + rules: sharedRules, + }, +]; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8d47fdc..7284faf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,42 +9,29 @@ "version": "0.1.0", "dependencies": { "@fontsource/inter": "^5.2.8", - "@tabler/icons-react": "3.11.0", - "axios": "1.7.7", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-router-dom": "6.27.0" + "@tabler/icons-react": "^3.35.0", + "axios": "^1.13.2", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router-dom": "^7.9.5" }, "devDependencies": { - "@babel/core": "7.26.0", - "@babel/preset-env": "7.26.0", - "@babel/preset-react": "7.26.3", - "@svgr/webpack": "8.1.0", - "babel-loader": "9.2.1", - "css-loader": "7.1.2", - "dotenv": "16.4.5", - "eslint": "8.57.0", - "eslint-plugin-react": "7.37.1", - "eslint-plugin-react-hooks": "4.6.0", - "html-webpack-plugin": "5.6.3", - "style-loader": "4.0.0", - "webpack": "5.95.0", - "webpack-cli": "5.1.4", - "webpack-dev-server": "5.1.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@babel/preset-react": "^7.28.5", + "@svgr/webpack": "^8.1.0", + "babel-loader": "^10.0.0", + "css-loader": "^7.1.2", + "dotenv": "^17.2.3", + "eslint": "^9.39.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^7.0.1", + "globals": "^16.5.0", + "html-webpack-plugin": "^5.6.4", + "style-loader": "^4.0.0", + "webpack": "^5.102.1", + "webpack-cli": "^6.0.1", + "webpack-dev-server": "^5.2.2" } }, "node_modules/@babel/code-frame": { @@ -63,9 +50,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "dev": true, "license": "MIT", "engines": { @@ -73,22 +60,22 @@ } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -139,14 +126,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -437,9 +424,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "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": { @@ -486,13 +473,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -502,14 +489,14 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -748,9 +735,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz", - "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", "dev": true, "license": "MIT", "dependencies": { @@ -836,14 +823,14 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -918,10 +905,27 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", "dev": true, "license": "MIT", "dependencies": { @@ -1018,9 +1022,9 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", "dev": true, "license": "MIT", "dependencies": { @@ -1084,16 +1088,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1238,9 +1242,9 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1624,80 +1628,81 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", - "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/compat-data": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.25.9", - "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.25.9", - "@babel/plugin-transform-block-scoping": "^7.25.9", - "@babel/plugin-transform-class-properties": "^7.25.9", - "@babel/plugin-transform-class-static-block": "^7.26.0", - "@babel/plugin-transform-classes": "^7.25.9", - "@babel/plugin-transform-computed-properties": "^7.25.9", - "@babel/plugin-transform-destructuring": "^7.25.9", - "@babel/plugin-transform-dotall-regex": "^7.25.9", - "@babel/plugin-transform-duplicate-keys": "^7.25.9", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^7.25.9", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-for-of": "^7.25.9", - "@babel/plugin-transform-function-name": "^7.25.9", - "@babel/plugin-transform-json-strings": "^7.25.9", - "@babel/plugin-transform-literals": "^7.25.9", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", - "@babel/plugin-transform-member-expression-literals": "^7.25.9", - "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-modules-systemjs": "^7.25.9", - "@babel/plugin-transform-modules-umd": "^7.25.9", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", - "@babel/plugin-transform-numeric-separator": "^7.25.9", - "@babel/plugin-transform-object-rest-spread": "^7.25.9", - "@babel/plugin-transform-object-super": "^7.25.9", - "@babel/plugin-transform-optional-catch-binding": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9", - "@babel/plugin-transform-private-methods": "^7.25.9", - "@babel/plugin-transform-private-property-in-object": "^7.25.9", - "@babel/plugin-transform-property-literals": "^7.25.9", - "@babel/plugin-transform-regenerator": "^7.25.9", - "@babel/plugin-transform-regexp-modifiers": "^7.26.0", - "@babel/plugin-transform-reserved-words": "^7.25.9", - "@babel/plugin-transform-shorthand-properties": "^7.25.9", - "@babel/plugin-transform-spread": "^7.25.9", - "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.25.9", - "@babel/plugin-transform-typeof-symbol": "^7.25.9", - "@babel/plugin-transform-unicode-escapes": "^7.25.9", - "@babel/plugin-transform-unicode-property-regex": "^7.25.9", - "@babel/plugin-transform-unicode-regex": "^7.25.9", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.5", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.4", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.38.1", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "engines": { @@ -1733,18 +1738,18 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", - "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-transform-react-display-name": "^7.25.9", - "@babel/plugin-transform-react-jsx": "^7.25.9", - "@babel/plugin-transform-react-jsx-development": "^7.25.9", - "@babel/plugin-transform-react-pure-annotations": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1789,18 +1794,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -1833,27 +1838,27 @@ "license": "MIT" }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=14.17.0" } }, "node_modules/@eslint-community/eslint-utils": { @@ -1885,17 +1890,83 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/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/@eslint/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -1903,7 +1974,7 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1927,6 +1998,19 @@ } } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1935,13 +2019,40 @@ "license": "MIT" }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@fontsource/inter": { @@ -1953,47 +2064,30 @@ "url": "https://github.com/sponsors/ayuhito" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/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/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -2008,13 +2102,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", @@ -2027,6 +2127,17 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -2192,53 +2303,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@remix-run/router": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", - "integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", @@ -2524,9 +2588,9 @@ } }, "node_modules/@tabler/icons": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.11.0.tgz", - "integrity": "sha512-/vZinJNvCYhdAB+RUsyCpanSPuOEKHHIZi4Uu0Bw7ilewHnQhCWUPrT704uHCRli2ROl7spADPmWzAqOganA5A==", + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.35.0.tgz", + "integrity": "sha512-yYXe+gJ56xlZFiXwV9zVoe3FWCGuZ/D7/G4ZIlDtGxSx5CGQK110wrnT29gUj52kEZoxqF7oURTk97GQxELOFQ==", "license": "MIT", "funding": { "type": "github", @@ -2534,12 +2598,12 @@ } }, "node_modules/@tabler/icons-react": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.11.0.tgz", - "integrity": "sha512-xHNBi9mns1slvqos+7LkP3ube4CjWrANMbxMaorzwzO9J/+y1sAEG/sN8CV8FmtpYW/9/gDR+OWCjjLLg0RmAw==", + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.35.0.tgz", + "integrity": "sha512-XG7t2DYf3DyHT5jxFNp5xyLVbL4hMJYJhiSdHADzAjLRYfL7AnjlRfiHDHeXxkb2N103rEIvTsBRazxXtAUz2g==", "license": "MIT", "dependencies": { - "@tabler/icons": "3.11.0" + "@tabler/icons": "3.35.0" }, "funding": { "type": "github", @@ -2601,6 +2665,28 @@ "@types/node": "*" } }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -2789,13 +2875,6 @@ "@types/node": "*" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -2958,45 +3037,45 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", + "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", + "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", + "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" }, "peerDependenciesMeta": { "webpack-dev-server": { @@ -3055,14 +3134,17 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, "peerDependencies": { - "acorn": "^8" + "acorn": "^8.14.0" } }, "node_modules/acorn-jsx": { @@ -3134,16 +3216,6 @@ "dev": true, "license": "MIT" }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -3382,89 +3454,96 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "node_modules/babel-loader": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", - "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", + "integrity": "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==", "dev": true, "license": "MIT", "dependencies": { - "find-cache-dir": "^4.0.0", - "schema-utils": "^4.0.0" + "find-up": "^5.0.0" }, "engines": { - "node": ">= 14.15.0" + "node": "^18.20.0 || ^20.10.0 || >=22.0.0" }, "peerDependencies": { "@babel/core": "^7.12.0", - "webpack": ">=5" + "webpack": ">=5.61.0" } }, - "node_modules/babel-loader/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "node_modules/babel-loader/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/babel-loader/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/babel-loader/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-loader/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/babel-plugin-polyfill-corejs2": { @@ -3493,14 +3572,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", - "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2", - "core-js-compat": "^3.38.0" + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -3936,13 +4015,6 @@ "node": ">= 12" } }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true, - "license": "ISC" - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -4441,19 +4513,6 @@ "node": ">=6" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -4535,9 +4594,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4843,86 +4902,89 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-react": { - "version": "7.37.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz", - "integrity": "sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==", + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, "license": "MIT", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", + "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", + "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.8", + "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", + "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", + "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "engines": { @@ -4933,16 +4995,23 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "node_modules/eslint-plugin-react/node_modules/doctrine": { @@ -5042,9 +5111,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5052,7 +5121,20 @@ "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5153,32 +5235,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5372,16 +5454,6 @@ "node": ">= 4.9.1" } }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -5396,16 +5468,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -5440,114 +5512,6 @@ "node": ">= 0.8" } }, - "node_modules/find-cache-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", - "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "common-path-prefix": "^3.0.0", - "pkg-dir": "^7.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^6.3.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -5573,18 +5537,17 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -5666,13 +5629,6 @@ "node": ">= 0.6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -5803,28 +5759,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -5863,16 +5797,13 @@ "license": "BSD-2-Clause" }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5914,13 +5845,6 @@ "dev": true, "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -6029,6 +5953,23 @@ "he": "bin/he" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -6075,23 +6016,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, "node_modules/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -6115,9 +6039,9 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", - "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.4.tgz", + "integrity": "sha512-V/PZeWsqhfpE27nKeX9EO2sbR+D17A+tLf6qU+ht66jdUsN0QLKJN27Z+1+gHrVMKgndBahes0PU6rRihDgHTw==", "dev": true, "license": "MIT", "dependencies": { @@ -6341,18 +6265,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -6710,16 +6622,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -6968,6 +6870,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -7157,6 +7060,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -7578,16 +7482,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/open": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", @@ -7774,16 +7668,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -8070,27 +7954,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -8128,28 +7991,24 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.2.0" } }, "node_modules/react-is": { @@ -8160,35 +8019,50 @@ "license": "MIT" }, "node_modules/react-router": { - "version": "6.27.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz", - "integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==", + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.5.tgz", + "integrity": "sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==", "license": "MIT", "dependencies": { - "@remix-run/router": "1.20.0" + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, "node_modules/react-router-dom": { - "version": "6.27.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz", - "integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==", + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.5.tgz", + "integrity": "sha512-mkEmq/K8tKN63Ae2M7Xgz3c9l9YNbY+NHH6NNeUmLA3kDkhKXRsNb/ZpxaEunvGo2/3YXdk5EJU3Hxp3ocaBPw==", "license": "MIT", "dependencies": { - "@remix-run/router": "1.20.0", - "react-router": "6.27.0" + "react-router": "7.9.5" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" } }, "node_modules/readable-stream": { @@ -8429,34 +8303,6 @@ "node": ">= 4" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -8470,30 +8316,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -8592,24 +8414,22 @@ "license": "MIT" }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 10.13.0" @@ -8619,6 +8439,43 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -8790,6 +8647,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -9498,63 +9361,6 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -9562,13 +9368,6 @@ "dev": true, "license": "MIT" }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/thingies": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", @@ -9653,19 +9452,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -9948,21 +9734,23 @@ } }, "node_modules/webpack": { - "version": "5.95.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", - "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", + "version": "5.102.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz", + "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.26.3", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", + "enhanced-resolve": "^5.17.3", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -9972,11 +9760,11 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -9995,43 +9783,40 @@ } }, "node_modules/webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", + "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, "license": "MIT", "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", + "@discoveryjs/json-ext": "^0.6.1", + "@webpack-cli/configtest": "^3.0.1", + "@webpack-cli/info": "^3.0.1", + "@webpack-cli/serve": "^3.0.1", "colorette": "^2.0.14", - "commander": "^10.0.1", + "commander": "^12.1.0", "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", + "envinfo": "^7.14.0", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^3.1.1", "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" + "webpack-merge": "^6.0.1" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "5.x.x" + "webpack": "^5.82.0" }, "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, "webpack-bundle-analyzer": { "optional": true }, @@ -10041,13 +9826,13 @@ } }, "node_modules/webpack-cli/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, "license": "MIT", "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/webpack-dev-middleware": { @@ -10080,43 +9865,6 @@ } } }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-dev-middleware/node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -10140,36 +9888,17 @@ "node": ">= 0.6" } }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpack-dev-server": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.1.0.tgz", - "integrity": "sha512-aQpaN81X6tXie1FoOB7xlMfCsN19pSvRAeYUHOdFWOlhpQ/LlbfTqYwwmEDFV0h8GGuqmCmKmT+pxcUV/Nt2gQ==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.2.tgz", + "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", "dev": true, "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", "@types/express": "^4.17.21", + "@types/express-serve-static-core": "^4.17.21", "@types/serve-index": "^1.9.4", "@types/serve-static": "^1.15.5", "@types/sockjs": "^0.3.36", @@ -10180,10 +9909,9 @@ "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", - "express": "^4.19.2", + "express": "^4.21.2", "graceful-fs": "^4.2.6", - "html-entities": "^2.4.0", - "http-proxy-middleware": "^2.0.3", + "http-proxy-middleware": "^2.0.9", "ipaddr.js": "^2.1.0", "launch-editor": "^2.6.1", "open": "^10.0.3", @@ -10218,76 +9946,32 @@ } } }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "node_modules/webpack-dev-server/node_modules/@types/express-serve-static-core": { + "version": "4.19.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", + "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" } }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", - "wildcard": "^2.0.0" + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-sources": { @@ -10454,13 +10138,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", @@ -10507,17 +10184,40 @@ "license": "ISC" }, "node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.20" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", + "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } } } } diff --git a/frontend/package.json b/frontend/package.json index a8b9ad3..af8a8c7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,27 +11,28 @@ }, "dependencies": { "@fontsource/inter": "^5.2.8", - "@tabler/icons-react": "3.11.0", - "axios": "1.7.7", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-router-dom": "6.27.0" + "@tabler/icons-react": "^3.35.0", + "axios": "^1.13.2", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router-dom": "^7.9.5" }, "devDependencies": { - "@babel/core": "7.26.0", - "@babel/preset-env": "7.26.0", - "@babel/preset-react": "7.26.3", - "eslint": "8.57.0", - "eslint-plugin-react": "7.37.1", - "eslint-plugin-react-hooks": "4.6.0", - "@svgr/webpack": "8.1.0", - "babel-loader": "9.2.1", - "css-loader": "7.1.2", - "dotenv": "16.4.5", - "html-webpack-plugin": "5.6.3", - "style-loader": "4.0.0", - "webpack": "5.95.0", - "webpack-cli": "5.1.4", - "webpack-dev-server": "5.1.0" + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@babel/preset-react": "^7.28.5", + "@svgr/webpack": "^8.1.0", + "babel-loader": "^10.0.0", + "css-loader": "^7.1.2", + "dotenv": "^17.2.3", + "eslint": "^9.39.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^7.0.1", + "globals": "^16.5.0", + "html-webpack-plugin": "^5.6.4", + "style-loader": "^4.0.0", + "webpack": "^5.102.1", + "webpack-cli": "^6.0.1", + "webpack-dev-server": "^5.2.2" } } diff --git a/frontend/src/desktop/db.js b/frontend/src/desktop/db.js index c1cdbf0..2e571ce 100644 --- a/frontend/src/desktop/db.js +++ b/frontend/src/desktop/db.js @@ -99,7 +99,7 @@ const withStore = async (mode, handler) => { } try { await done; - } catch (suppressed) { + } catch { // noop – prefer original error } throw error; diff --git a/frontend/src/desktop/workspaceEngine.js b/frontend/src/desktop/workspaceEngine.js index 3effcb7..08e5a38 100644 --- a/frontend/src/desktop/workspaceEngine.js +++ b/frontend/src/desktop/workspaceEngine.js @@ -1223,7 +1223,6 @@ export const useWorkspaceSnapshot = (engine, useSyncExternalStoreHook) => { }; /* istanbul ignore next */ -/* eslint-disable no-undef */ if (typeof module !== 'undefined' && module && module.exports) { module.exports = { WorkspaceEngine, @@ -1245,4 +1244,3 @@ if (typeof module !== 'undefined' && module && module.exports) { useWorkspaceSnapshot, }; } -/* eslint-enable no-undef */ diff --git a/frontend/src/documents/hooks/useBulkDocumentActions.js b/frontend/src/documents/hooks/useBulkDocumentActions.js index 317ee2e..64bdea9 100644 --- a/frontend/src/documents/hooks/useBulkDocumentActions.js +++ b/frontend/src/documents/hooks/useBulkDocumentActions.js @@ -31,7 +31,7 @@ const useBulkDocumentActions = ({ if (!target) { try { target = await handleCorrespondentCreate({ name: trimmed }); - } catch (error) { + } catch { return; } } @@ -160,7 +160,6 @@ const useBulkDocumentActions = ({ if (folderIds.length) { for (const folderId of folderIds) { - // eslint-disable-next-line no-await-in-loop const success = await handleFolderDelete(folderId, { showMessage: false, manageLoading: false }); if (!success) { foldersOk = false; diff --git a/frontend/src/documents/useInlineRename.js b/frontend/src/documents/useInlineRename.js index a2b2082..0961336 100644 --- a/frontend/src/documents/useInlineRename.js +++ b/frontend/src/documents/useInlineRename.js @@ -97,7 +97,7 @@ const useInlineRename = ( } resetState(); return true; - } catch (error) { + } catch { return false; } finally { setSavingId((current) => (current === entityId ? null : current)); diff --git a/frontend/src/hooks/documents/useDocumentCorrespondentActions.js b/frontend/src/hooks/documents/useDocumentCorrespondentActions.js index 8402795..b618d47 100644 --- a/frontend/src/hooks/documents/useDocumentCorrespondentActions.js +++ b/frontend/src/hooks/documents/useDocumentCorrespondentActions.js @@ -87,7 +87,7 @@ const useDocumentCorrespondentActions = ({ if (!target) { try { target = await handleCorrespondentCreate({ name: trimmed }); - } catch (error) { + } catch { return; } } @@ -127,4 +127,3 @@ const useDocumentCorrespondentActions = ({ }; export default useDocumentCorrespondentActions; - diff --git a/frontend/src/hooks/documents/useDocumentUploads.js b/frontend/src/hooks/documents/useDocumentUploads.js index 50b6d2d..26dab19 100644 --- a/frontend/src/hooks/documents/useDocumentUploads.js +++ b/frontend/src/hooks/documents/useDocumentUploads.js @@ -175,7 +175,6 @@ const useDocumentUploads = ({ const entries = []; let batch = []; do { - // eslint-disable-next-line no-await-in-loop batch = await new Promise((resolve, reject) => reader.readEntries(resolve, reject)); if (batch.length) { entries.push(...batch); @@ -203,7 +202,6 @@ const useDocumentUploads = ({ const reader = entry.createReader(); const entries = await readAllEntries(reader); for (const child of entries) { - // eslint-disable-next-line no-await-in-loop await walkEntry(child, nextAncestors); } } @@ -306,7 +304,6 @@ const useDocumentUploads = ({ updateQueueItem(queueItem.id, patch); Object.assign(queueItem, patch); } - // eslint-disable-next-line no-await-in-loop const destinationId = segments.length ? await ensureFolderPathOnServer(baseFolderId, segments) : baseFolderId; @@ -316,7 +313,6 @@ const useDocumentUploads = ({ (targetFolderId && targetFolderId !== 'root' ? targetFolderId : 'root'); try { - // eslint-disable-next-line no-await-in-loop const { duplicate, statusCode, document, conflictDocumentId } = await uploadFile( file, uploadTarget, diff --git a/frontend/src/hooks/documents/useFolderTreeActions.js b/frontend/src/hooks/documents/useFolderTreeActions.js index 8103619..29da7b1 100644 --- a/frontend/src/hooks/documents/useFolderTreeActions.js +++ b/frontend/src/hooks/documents/useFolderTreeActions.js @@ -96,7 +96,6 @@ const useFolderTreeActions = ({ const refreshTargets = new Set([previousParentKey, targetKey]); for (const key of refreshTargets) { - // eslint-disable-next-line no-await-in-loop await ensureFolderData(key === 'root' ? 'root' : key, { force: true, prefetchDepth: 1 }); } @@ -112,7 +111,6 @@ const useFolderTreeActions = ({ const refreshTargets = new Set([previousParentKey, targetKey]); for (const key of refreshTargets) { - // eslint-disable-next-line no-await-in-loop await ensureFolderData(key === 'root' ? 'root' : key, { force: true, prefetchDepth: 1 }); } } @@ -516,7 +514,6 @@ const useFolderTreeActions = ({ } for (const sourceId of folderIds) { - // eslint-disable-next-line no-await-in-loop await moveFolder(sourceId, folderId); } } diff --git a/frontend/src/settings/sections/ApiTokensSection.jsx b/frontend/src/settings/sections/ApiTokensSection.jsx index b3ea68c..afe743a 100644 --- a/frontend/src/settings/sections/ApiTokensSection.jsx +++ b/frontend/src/settings/sections/ApiTokensSection.jsx @@ -132,7 +132,7 @@ const ApiTokensSection = ({ await navigator.clipboard.writeText(createdToken); showSuccess(); return; - } catch (error) { + } catch { // Some browsers expose writeText but still reject outside secure context setCanCopyToken(false); } diff --git a/frontend/src/ui/BreadcrumbTrail.jsx b/frontend/src/ui/BreadcrumbTrail.jsx index ea21983..3ea89da 100644 --- a/frontend/src/ui/BreadcrumbTrail.jsx +++ b/frontend/src/ui/BreadcrumbTrail.jsx @@ -115,18 +115,15 @@ const BreadcrumbTrail = ({ for (let start = 0; start < entryNodes.length; start += 1) { entryNodes.forEach((node, index) => { // Hide entries that fall before the visible window. - // eslint-disable-next-line no-param-reassign node.style.display = index < start ? 'none' : ''; }); separatorNodes.forEach((node) => { const targetIndex = Number(node.getAttribute('data-target-index')); - // eslint-disable-next-line no-param-reassign node.style.display = targetIndex < Math.max(start, 1) ? 'none' : ''; }); if (ellipsisNode) { - // eslint-disable-next-line no-param-reassign ellipsisNode.style.display = start > 0 ? '' : 'none'; } @@ -134,17 +131,14 @@ const BreadcrumbTrail = ({ } entryNodes.forEach((node, index) => { - // eslint-disable-next-line no-param-reassign node.style.display = originalEntryDisplay[index] ?? ''; }); separatorNodes.forEach((node, index) => { - // eslint-disable-next-line no-param-reassign node.style.display = originalSeparatorDisplay[index] ?? ''; }); if (ellipsisNode) { - // eslint-disable-next-line no-param-reassign ellipsisNode.style.display = originalEllipsisDisplay ?? 'none'; } diff --git a/frontend/src/utils/ocr.js b/frontend/src/utils/ocr.js index 3acbb2c..b2b8177 100644 --- a/frontend/src/utils/ocr.js +++ b/frontend/src/utils/ocr.js @@ -66,7 +66,7 @@ export async function openOcrTextInNewTab(options) { if (popupAvailable) { try { popup.opener = null; - } catch (error) { + } catch { /* ignore */ } } @@ -83,7 +83,7 @@ export async function openOcrTextInNewTab(options) { if (popupAvailable) { try { popup.location.replace(url); - } catch (navigationError) { + } catch { try { popup.location.href = url; } catch (secondError) { @@ -96,7 +96,7 @@ export async function openOcrTextInNewTab(options) { if (finalWindow) { try { finalWindow.opener = null; - } catch (error) { + } catch { /* ignore */ } } From ab81e76206d7b635b39a50b1a508f856424f4a1e Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Mon, 10 Nov 2025 15:01:20 +0100 Subject: [PATCH 02/13] tweak --- frontend/src/styles/detail/detail-panels.css | 9 ++++++--- frontend/src/styles/sidebar/sidebar.css | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/styles/detail/detail-panels.css b/frontend/src/styles/detail/detail-panels.css index d559895..9ec4119 100644 --- a/frontend/src/styles/detail/detail-panels.css +++ b/frontend/src/styles/detail/detail-panels.css @@ -172,12 +172,15 @@ .selection-assignment__menu { font-size: 0.95rem; font-weight: 400; - padding: 0.4rem 0; + display: flex; + flex-direction: column; + gap: 0; + padding: 0; max-width: min(22rem, 90vw); } .selection-assignment__header { - padding: 0.4rem 0.75rem 0.3rem; + padding: 0.5rem; border-bottom: 1px solid var(--border-subtle); } @@ -200,7 +203,7 @@ .selection-assignment__list { max-height: 240px; overflow-y: auto; - padding: 0 0.75rem; + padding: 0 0.25rem 0.25rem; } .selection-assignment__item { diff --git a/frontend/src/styles/sidebar/sidebar.css b/frontend/src/styles/sidebar/sidebar.css index 2adf0bd..6a21907 100644 --- a/frontend/src/styles/sidebar/sidebar.css +++ b/frontend/src/styles/sidebar/sidebar.css @@ -263,7 +263,7 @@ justify-content: flex-start; gap: 0.5rem; width: 100%; - padding: 0.45rem 0.75rem; + padding: 0.5rem 0.75rem; border: none; border-radius: 0.4rem; background: none; From 8820ff1c15edb0a12c921a5d4fba1a69cf3516ba Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Mon, 10 Nov 2025 21:25:11 +0100 Subject: [PATCH 03/13] fixes --- .../src/documents/SelectionAssignmentMenu.jsx | 1 + .../components/CapabilityDropdown.jsx | 1 + frontend/src/styles/base/theme.css | 3 + frontend/src/styles/detail/detail-panels.css | 10 +- frontend/src/styles/documents/controls.css | 5 +- .../src/styles/documents/panel-sections.css | 24 +++- frontend/src/styles/layout/structure.css | 2 +- frontend/src/styles/sidebar/sidebar.css | 13 +- frontend/src/ui/BreadcrumbTrail.jsx | 125 ++++++++++++------ frontend/src/ui/QuickAddMenu.jsx | 24 +++- frontend/src/ui/useFloatingMenu.js | 4 +- 11 files changed, 155 insertions(+), 57 deletions(-) diff --git a/frontend/src/documents/SelectionAssignmentMenu.jsx b/frontend/src/documents/SelectionAssignmentMenu.jsx index 7f2742e..e5ff17b 100644 --- a/frontend/src/documents/SelectionAssignmentMenu.jsx +++ b/frontend/src/documents/SelectionAssignmentMenu.jsx @@ -181,6 +181,7 @@ const SelectionAssignmentMenu = ({ ref={menuRef} style={menuStyle || undefined} role="menu" + data-floating-position >
{total ? ( options.map((option) => { diff --git a/frontend/src/styles/base/theme.css b/frontend/src/styles/base/theme.css index 6b7db9f..44bbe35 100644 --- a/frontend/src/styles/base/theme.css +++ b/frontend/src/styles/base/theme.css @@ -14,6 +14,7 @@ --surface-subtle: oklch(0.96 0.002 calc(var(--neutral-hue) + var(--surface-hue-shift))); --fg: oklch(0.32 0.005 calc(var(--neutral-hue) + var(--foreground-hue-offset))); --muted: oklch(0.54 0.008 calc(var(--neutral-hue) + var(--foreground-hue-offset))); + --muted-subtle: color-mix(in oklch, var(--muted) 55%, var(--border)); --sidebar-fg: oklch(0.56 0.007 calc(var(--neutral-hue) + var(--foreground-hue-offset))); --border: oklch(0.92 0.002 calc(var(--neutral-hue) + var(--foreground-hue-offset))); @@ -112,6 +113,7 @@ --surface-subtle: oklch(0.23 0.012 calc(var(--dark-neutral-hue) + var(--surface-hue-shift))); --fg: oklch(0.89 0.015 var(--dark-foreground-hue)); --muted: oklch(0.72 0.02 var(--dark-foreground-hue)); + --muted-subtle: color-mix(in oklch, var(--muted) 45%, var(--border)); --sidebar-fg: oklch(0.78 0.02 var(--dark-foreground-hue)); --border: oklch(0.33 0.01 var(--dark-foreground-hue)); @@ -189,6 +191,7 @@ --surface-subtle: oklch(0.23 0.012 calc(var(--dark-neutral-hue) + var(--surface-hue-shift))); --fg: oklch(0.89 0.015 var(--dark-foreground-hue)); --muted: oklch(0.72 0.02 var(--dark-foreground-hue)); + --muted-subtle: color-mix(in oklch, var(--muted) 45%, var(--border)); --sidebar-fg: oklch(0.78 0.02 var(--dark-foreground-hue)); --border: oklch(0.33 0.01 var(--dark-foreground-hue)); diff --git a/frontend/src/styles/detail/detail-panels.css b/frontend/src/styles/detail/detail-panels.css index 9ec4119..1afcd0e 100644 --- a/frontend/src/styles/detail/detail-panels.css +++ b/frontend/src/styles/detail/detail-panels.css @@ -80,6 +80,8 @@ } .quick-add { + --quick-add-menu-offset: 0.35rem; + --quick-add-menu-min-width: 220px; display: inline-flex; align-items: center; position: relative; @@ -128,10 +130,6 @@ gap: 0.25rem; } -.quick-add__menu { - padding: 0.25rem 0; -} - .quick-add__form { display: flex; align-items: center; @@ -196,8 +194,8 @@ .selection-assignment__header input:focus-visible { outline: none; - border-color: var(--selection-border); - box-shadow: 0 0 0 2px color-mix(in oklch, var(--selection) 25%, transparent); + border-color: color-mix(in oklch, var(--accent) 60%, transparent); + box-shadow: 0 0 0 1px color-mix(in oklch, var(--accent) 35%, transparent); } .selection-assignment__list { diff --git a/frontend/src/styles/documents/controls.css b/frontend/src/styles/documents/controls.css index 8c5c8ac..24642cd 100644 --- a/frontend/src/styles/documents/controls.css +++ b/frontend/src/styles/documents/controls.css @@ -44,6 +44,10 @@ position: relative; } +.documents-sort__quickmenu { + --quick-add-menu-min-width: 200px; +} + .documents-sort__trigger { display: inline-flex; align-items: center; @@ -105,4 +109,3 @@ width: 1.1rem; height: 1.1rem; } - diff --git a/frontend/src/styles/documents/panel-sections.css b/frontend/src/styles/documents/panel-sections.css index de07a4f..3899f0c 100644 --- a/frontend/src/styles/documents/panel-sections.css +++ b/frontend/src/styles/documents/panel-sections.css @@ -84,19 +84,36 @@ cursor: default; } +.breadcrumb-trail--measure .breadcrumb-trail__link, +.breadcrumb-trail--measure .breadcrumb-trail__ellipsis-button { + max-width: none; + overflow: visible; +} + +button.breadcrumb-trail__link, +.breadcrumb-trail__ellipsis-button { + padding: 0.25rem; + background: none; + border-radius: 0.25rem; +} + .breadcrumb-trail__link:not(.is-current) { cursor: pointer; color: var(--accent); } .breadcrumb-trail__link:not(.is-current):hover, -.breadcrumb-trail__link:not(.is-current):focus-visible { +.breadcrumb-trail__link:not(.is-current):focus-visible, +.panel-header .breadcrumb-trail__link:not(.is-current):hover, +.panel-header .breadcrumb-trail__link:not(.is-current):focus-visible { text-decoration: underline; + background: var(--accent-soft); + color: var(--accent); } .breadcrumb-trail__separator { - color: var(--muted); - margin: 0 0.2rem; + color: var(--muted-subtle); + margin: 0; } .breadcrumb-trail__ellipsis { @@ -130,4 +147,3 @@ .panel-section__body.scrollable { overflow-y: auto; } - diff --git a/frontend/src/styles/layout/structure.css b/frontend/src/styles/layout/structure.css index 4f07e1e..e2712c6 100644 --- a/frontend/src/styles/layout/structure.css +++ b/frontend/src/styles/layout/structure.css @@ -98,7 +98,7 @@ .main-content__actions-divider { display: inline-flex; align-items: center; - color: var(--muted); + color: var(--muted-subtle); } .main-content__title { diff --git a/frontend/src/styles/sidebar/sidebar.css b/frontend/src/styles/sidebar/sidebar.css index 6a21907..4d38da3 100644 --- a/frontend/src/styles/sidebar/sidebar.css +++ b/frontend/src/styles/sidebar/sidebar.css @@ -229,14 +229,19 @@ border-radius: 0.5rem; box-shadow: 0 12px 28px var(--shadow-strong); min-width: 220px; - z-index: 20; + z-index: 2500000; overflow: hidden; } +.menu[data-floating-position] { + top: auto; + left: auto; + min-width: var(--floating-min-width, 220px); +} + .menu__list { - max-height: 260px; overflow-y: auto; - padding: 0.35rem 0.5rem; + padding: 0.25rem; display: flex; flex-direction: column; gap: 0.25rem; @@ -265,7 +270,7 @@ width: 100%; padding: 0.5rem 0.75rem; border: none; - border-radius: 0.4rem; + border-radius: 0.25rem; background: none; color: var(--sidebar-fg); font: inherit; diff --git a/frontend/src/ui/BreadcrumbTrail.jsx b/frontend/src/ui/BreadcrumbTrail.jsx index 3ea89da..a6fed37 100644 --- a/frontend/src/ui/BreadcrumbTrail.jsx +++ b/frontend/src/ui/BreadcrumbTrail.jsx @@ -24,7 +24,8 @@ const normalizeEntries = (entries) => const ELLIPSIS = { id: '__breadcrumbs_ellipsis__', label: '…', onClick: null, raw: null }; const WIDTH_TOLERANCE = 1; -const WIDTH_BUFFER_RATIO = 0.99; +const WIDTH_BUFFER_RATIO = 0.95; +const WIDTH_CHANGE_TOLERANCE = 0.25; const BreadcrumbTrail = ({ entries = [], @@ -43,6 +44,7 @@ const BreadcrumbTrail = ({ const ellipsisButtonRef = useRef(null); const [availableWidth, setAvailableWidth] = useState(null); const [startIndex, setStartIndex] = useState(0); + const measureRafRef = useRef(null); const { isOpen: ellipsisMenuOpen, @@ -58,18 +60,13 @@ const BreadcrumbTrail = ({ }); useEffect(() => { - setStartIndex(0); closeEllipsisMenu(); }, [normalized, shouldTruncateFromStart, closeEllipsisMenu]); useEffect(() => { - const container = containerRef.current; - if (!container || typeof ResizeObserver === 'undefined') { - return undefined; - } - - const updateWidth = () => { - const host = containerRef.current; + const resolveHost = () => containerRef.current?.parentElement || containerRef.current; + const measure = () => { + const host = resolveHost(); if (!host) { return; } @@ -77,14 +74,56 @@ const BreadcrumbTrail = ({ if (!nextWidth) { return; } - setAvailableWidth((prev) => (prev && Math.abs(prev - nextWidth) < 0.5 ? prev : nextWidth)); + setAvailableWidth((prev) => ( + prev && Math.abs(prev - nextWidth) < WIDTH_CHANGE_TOLERANCE ? prev : nextWidth + )); }; - updateWidth(); + const scheduleMeasure = () => { + if (typeof window === 'undefined' || typeof window.requestAnimationFrame !== 'function') { + measure(); + return; + } + if (measureRafRef.current) { + cancelAnimationFrame(measureRafRef.current); + } + measureRafRef.current = window.requestAnimationFrame(() => { + measureRafRef.current = null; + measure(); + }); + }; - const observer = new ResizeObserver(updateWidth); - observer.observe(container.parentElement || container); - return () => observer.disconnect(); + scheduleMeasure(); + + if (typeof ResizeObserver === 'undefined') { + return () => { + if (measureRafRef.current) { + cancelAnimationFrame(measureRafRef.current); + measureRafRef.current = null; + } + }; + } + + const host = resolveHost(); + if (!host) { + return () => { + if (measureRafRef.current) { + cancelAnimationFrame(measureRafRef.current); + measureRafRef.current = null; + } + }; + } + + const observer = new ResizeObserver(scheduleMeasure); + observer.observe(host); + + return () => { + observer.disconnect(); + if (measureRafRef.current) { + cancelAnimationFrame(measureRafRef.current); + measureRafRef.current = null; + } + }; }, []); useLayoutEffect(() => { @@ -94,7 +133,8 @@ const BreadcrumbTrail = ({ const container = containerRef.current; const measurement = measurementRef.current; - if (!container || !measurement) { + const host = container?.parentElement || container; + if (!container || !measurement || !host) { return; } @@ -142,7 +182,7 @@ const BreadcrumbTrail = ({ ellipsisNode.style.display = originalEllipsisDisplay ?? 'none'; } - const available = availableWidth ?? container.getBoundingClientRect().width; + const available = availableWidth ?? host.getBoundingClientRect().width; if (!available || !widths.length) { return; } @@ -283,33 +323,43 @@ const BreadcrumbTrail = ({ className="breadcrumb-trail breadcrumb-trail--measure" aria-hidden="true" > - {ELLIPSIS.label} - - {measurementEntries.map((entry, index) => ( - - {index > 0 ? ( - + {measurementEntries.map((entry, index) => { + const isLast = index === measurementEntries.length - 1; + const isInteractive = Boolean(entry.onClick) && !isLast; + const MeasurementTag = isInteractive ? 'button' : 'span'; + + return ( + + {index > 0 ? ( + + {separator} + + ) : null} + - {separator} - - ) : null} - - {entry.label} - - - ))} + {entry.label} + + + ); + })} {ellipsisMenuOpen && hasHiddenEntries @@ -321,6 +371,7 @@ const BreadcrumbTrail = ({ role="menu" ref={ellipsisMenuRef} style={ellipsisMenuStyle} + data-floating-position >
{hiddenEntries.map((hiddenEntry) => ( diff --git a/frontend/src/ui/QuickAddMenu.jsx b/frontend/src/ui/QuickAddMenu.jsx index f239735..2def0e2 100644 --- a/frontend/src/ui/QuickAddMenu.jsx +++ b/frontend/src/ui/QuickAddMenu.jsx @@ -144,6 +144,23 @@ const QuickAddMenu = ({ ); const canCreate = Boolean(onCreate); + const isAnchoredMenu = positionStrategy === 'absolute' && align === 'start'; + const menuClassName = 'menu menu--floating'; + const anchoredMenuStyle = isAnchoredMenu && menuStyle + ? { + top: menuStyle.top, + left: menuStyle.left, + ...(menuStyle.width ? { width: menuStyle.width } : null), + } + : undefined; + const menuInlineStyle = isAnchoredMenu ? anchoredMenuStyle : menuStyle || undefined; + const hasFloatingWidthVar = Boolean(menuInlineStyle && Object.prototype.hasOwnProperty.call(menuInlineStyle, '--floating-min-width')); + const menuStyleWithVar = hasFloatingWidthVar + ? menuInlineStyle + : { + ...(menuInlineStyle || {}), + '--floating-min-width': `${Math.max(menuMinWidth, 0)}px`, + }; return (
@@ -162,10 +179,11 @@ const QuickAddMenu = ({ {isOpen ? (
{canCreate ? (
@@ -183,7 +201,7 @@ const QuickAddMenu = ({
) : null} -
+
{filteredOptions.length ? ( filteredOptions.map((option) => { const key = option.id ?? option.index; diff --git a/frontend/src/ui/useFloatingMenu.js b/frontend/src/ui/useFloatingMenu.js index 3140ba6..e46e113 100644 --- a/frontend/src/ui/useFloatingMenu.js +++ b/frontend/src/ui/useFloatingMenu.js @@ -28,8 +28,10 @@ const formatStyle = (metrics) => { position: metrics.strategy === 'absolute' ? 'absolute' : 'fixed', top: metrics.top, left: metrics.left, - minWidth: metrics.minWidth, }; + if (typeof metrics.minWidth === 'number') { + style['--floating-min-width'] = `${Math.max(metrics.minWidth, 0)}px`; + } if (metrics.width) { style.width = metrics.width; } From 0a1416ef92b2e4d016e4087cc28543c02828ae6f Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Mon, 10 Nov 2025 22:08:46 +0100 Subject: [PATCH 04/13] pixelpeeping --- frontend/src/sidebar/Sidebar.jsx | 44 ++++++++++---------- frontend/src/styles/detail/detail-panels.css | 2 +- frontend/src/styles/sidebar/sidebar.css | 31 +++++++++++--- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/frontend/src/sidebar/Sidebar.jsx b/frontend/src/sidebar/Sidebar.jsx index 84b084c..96e68bb 100644 --- a/frontend/src/sidebar/Sidebar.jsx +++ b/frontend/src/sidebar/Sidebar.jsx @@ -512,9 +512,9 @@ const Sidebar = ({ style={tenantMenuStyle} > {showTenantList ? ( - <> +
Switch tenant
-
+
{tenants.map((tenant) => { const tenantId = tenant?.id || null; const isActive = tenantId === activeTenantId; @@ -523,7 +523,7 @@ const Sidebar = ({
- +
) : null} -
- - +
+
+ + +
{themeMenuSection}
, diff --git a/frontend/src/styles/detail/detail-panels.css b/frontend/src/styles/detail/detail-panels.css index 1afcd0e..91a4154 100644 --- a/frontend/src/styles/detail/detail-panels.css +++ b/frontend/src/styles/detail/detail-panels.css @@ -199,7 +199,7 @@ } .selection-assignment__list { - max-height: 240px; + max-height: max(240px, 50vh); overflow-y: auto; padding: 0 0.25rem 0.25rem; } diff --git a/frontend/src/styles/sidebar/sidebar.css b/frontend/src/styles/sidebar/sidebar.css index 4d38da3..fdb64a4 100644 --- a/frontend/src/styles/sidebar/sidebar.css +++ b/frontend/src/styles/sidebar/sidebar.css @@ -13,7 +13,7 @@ align-items: center; gap: 0.22rem; padding: 0.32rem 0.48rem; - border-radius: 8px; + border-radius: 0.5rem; cursor: pointer; color: inherit; transition: background 0.12s ease, color 0.12s ease; @@ -83,12 +83,12 @@ transform: translateY(-50%); display: flex; gap: 0; + margin-right: 0.3rem; opacity: 0; pointer-events: none; transition: opacity 0.12s ease; background-color: var(--surface-overlay); - border-radius: 8px; - padding: 0 0.18rem; + border-radius: 0.2rem; } .folder-row__actions .icon-button { @@ -99,6 +99,7 @@ .folder-row:focus-within .folder-row__actions { opacity: 1; pointer-events: auto; + background-color: var(--surface-overlay); } .folder-children { @@ -304,6 +305,7 @@ flex: 1; overflow: hidden; text-overflow: ellipsis; + text-align: left; } .menu__check-slot { @@ -326,15 +328,18 @@ font-size: 0.85rem; } -.menu__footer { - border-top: 1px solid var(--border-muted, var(--border)); +.menu__wrapper { padding: 0.35rem 0.5rem; display: flex; flex-direction: column; gap: 0.25rem; } -.menu--simple .menu__footer { +.menu__section { + border-top: 1px solid var(--border-muted, var(--border)); +} + +.menu__section:first-of-type { border-top: none; } @@ -396,6 +401,20 @@ transition: background 0.15s ease, color 0.15s ease; } +.menu__button .menu__check-slot { + width: 1rem; + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--accent); +} + +.menu__button.active { + font-weight: 600; + color: var(--accent); + background: var(--accent-soft); +} + .menu__button:hover, .menu__button:focus-visible { background: var(--sidebar-hover-bg); From 992d7038e5763fed5e31e38ceef880525a94dcad Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Mon, 10 Nov 2025 22:39:29 +0100 Subject: [PATCH 05/13] restore drag preview --- .../documents/useDocumentDragHandlers.js | 86 ++++++++++++++++--- frontend/src/styles/documents/viewer.css | 13 ++- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/frontend/src/hooks/documents/useDocumentDragHandlers.js b/frontend/src/hooks/documents/useDocumentDragHandlers.js index 3a09fee..9662e89 100644 --- a/frontend/src/hooks/documents/useDocumentDragHandlers.js +++ b/frontend/src/hooks/documents/useDocumentDragHandlers.js @@ -53,24 +53,90 @@ const useDocumentDragHandlers = ({ const wrapper = document.createElement('div'); wrapper.className = 'document-drag-preview'; - wrapper.style.width = `${canvasSize}px`; - wrapper.style.height = `${canvasSize}px`; + wrapper.style.setProperty('--drag-preview-size', `${canvasSize}px`); visibleItems.forEach((item, index) => { - const slot = document.createElement('div'); - slot.className = 'document-drag-preview__item'; - slot.style.setProperty('--index', String(index)); - slot.style.width = `${size}px`; - slot.style.height = `${size}px`; + const layer = document.createElement('div'); + layer.className = 'document-drag-preview__item'; + layer.style.setProperty('--index', String(index)); + const rotationMagnitude = Math.random() * 8 + 2; + const rotation = (index % 2 === 0 ? 1 : -1) * rotationMagnitude; + layer.style.setProperty('--rotation-deg', `${rotation}deg`); if (item.type === 'document') { - slot.textContent = item.payload?.title || 'Document'; + const doc = item.payload; + const rowEl = doc?.id + ? document.getElementById(`document-row-${doc.id}`) + || document.getElementById(`document-card-${doc.id}`) + : null; + const wrapperEl = rowEl?.querySelector('.document-thumbnail-wrapper'); + const thumbnailEl = rowEl?.querySelector('.document-thumbnail'); + const placeholderEl = rowEl?.querySelector('.thumb-placeholder'); + const aspectAttr = wrapperEl?.dataset?.thumbnailAspect; + const aspectRatio = aspectAttr ? parseFloat(aspectAttr) : null; + + let thumbWidth = size; + let thumbHeight = size; + if (Number.isFinite(aspectRatio) && aspectRatio > 0) { + if (aspectRatio >= 1) { + thumbWidth = size; + thumbHeight = Math.max(size / aspectRatio, size * 0.5); + } else { + thumbHeight = size; + thumbWidth = Math.max(size * aspectRatio, size * 0.5); + } + } + layer.style.width = `${Math.round(thumbWidth)}px`; + layer.style.height = `${Math.round(thumbHeight)}px`; + + const thumbSrc = thumbnailEl?.currentSrc || thumbnailEl?.src || null; + if (thumbSrc) { + layer.classList.add('document-drag-preview__item--image'); + layer.style.backgroundImage = `url("${thumbSrc}")`; + } else if (placeholderEl instanceof HTMLElement) { + const clone = placeholderEl.cloneNode(true); + clone.style.pointerEvents = 'none'; + layer.appendChild(clone); + } else { + layer.textContent = doc?.title || 'Document'; + } } else { - slot.textContent = 'Folder'; + const folderId = item.payload; + const rowEl = folderId ? document.getElementById(`folder-row-${folderId}`) : null; + const iconEl = rowEl?.querySelector('.thumb-icon'); + layer.style.width = `${size}px`; + layer.style.height = `${size}px`; + + let content = null; + if (iconEl instanceof HTMLElement) { + content = iconEl.cloneNode(true); + content.classList.add('document-drag-preview__folder-thumb'); + const svg = content.querySelector('svg'); + if (svg) { + svg.setAttribute('width', '48'); + svg.setAttribute('height', '48'); + } + } + + if (!content) { + content = document.createElement('div'); + content.className = 'document-drag-preview__folder-placeholder'; + content.textContent = 'Folder'; + } + + layer.appendChild(content); } - wrapper.appendChild(slot); + + wrapper.appendChild(layer); }); + if (totalCount > 1) { + const badge = document.createElement('div'); + badge.className = 'document-drag-preview__count'; + badge.textContent = `${totalCount}`; + wrapper.appendChild(badge); + } + document.body.appendChild(wrapper); dragPreviewRef.current = wrapper; return wrapper; diff --git a/frontend/src/styles/documents/viewer.css b/frontend/src/styles/documents/viewer.css index 74af8df..c73de23 100644 --- a/frontend/src/styles/documents/viewer.css +++ b/frontend/src/styles/documents/viewer.css @@ -17,7 +17,7 @@ z-index: 9999; } -.document-drag-preview__thumb { +.document-drag-preview__item { position: absolute; top: 50%; left: 50%; @@ -38,23 +38,23 @@ transform-origin: center; } -.document-drag-preview__thumb--image { +.document-drag-preview__item--image { background-color: #000; background-repeat: no-repeat; background-size: contain; background-position: center; } -.document-drag-preview__thumb .document-thumbnail, -.document-drag-preview__thumb img { +.document-drag-preview__item .document-thumbnail, +.document-drag-preview__item img { width: 100%; height: 100%; object-fit: cover; pointer-events: none; } -.document-drag-preview__thumb .thumb-placeholder, -.document-drag-preview__thumb .thumb-placeholder * { +.document-drag-preview__item .thumb-placeholder, +.document-drag-preview__item .thumb-placeholder * { width: 100%; height: 100%; display: flex; @@ -332,4 +332,3 @@ width: 1rem; height: 1rem; } - From 70b9443e6602f0ef48feda17a42da34a18d4aec0 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Tue, 11 Nov 2025 00:48:07 +0100 Subject: [PATCH 06/13] outline --- frontend/src/documents/DocumentsList.jsx | 168 +++++++++--------- .../src/documents/panel/DocumentsPanel.jsx | 10 -- frontend/src/documents/useEntryPointer.js | 41 ++--- .../documents/useDocumentDragHandlers.js | 38 +++- .../hooks/documents/useDocumentsWorkspace.js | 21 +-- frontend/src/hooks/documents/useFolderTree.js | 5 +- .../src/styles/documents/drag-preview.css | 76 ++++++++ frontend/src/styles/documents/listing.css | 24 ++- frontend/src/styles/documents/viewer.css | 6 + frontend/src/styles/index.css | 1 + frontend/src/styles/sidebar/sidebar.css | 5 + 11 files changed, 258 insertions(+), 137 deletions(-) create mode 100644 frontend/src/styles/documents/drag-preview.css diff --git a/frontend/src/documents/DocumentsList.jsx b/frontend/src/documents/DocumentsList.jsx index 714b2d8..d17fdce 100644 --- a/frontend/src/documents/DocumentsList.jsx +++ b/frontend/src/documents/DocumentsList.jsx @@ -139,92 +139,96 @@ const DocumentsList = ({
- -
- - - {isFolderEditing ? ( - - setFolderDraft(event.target.value)} - onClick={(event) => event.stopPropagation()} - onKeyDown={(event) => { - if (event.key === 'Enter') { + +
+
+
+ + + {isFolderEditing ? ( + + setFolderDraft(event.target.value)} + onClick={(event) => event.stopPropagation()} + onKeyDown={(event) => { + if (event.key === 'Enter') { + event.preventDefault(); + submitFolderEditing(folder); + } else if (event.key === 'Escape') { + event.preventDefault(); + cancelFolderEditing(event); + } + }} + onBlur={(event) => { + const nextFocus = event.relatedTarget; + if (!nextFocus || !event.currentTarget.parentElement?.contains(nextFocus)) { + cancelFolderEditing(); + } + }} + /> + + + + ) : ( + { + if (!allowInlineFolderEdit) { + return; + } event.preventDefault(); - submitFolderEditing(folder); - } else if (event.key === 'Escape') { - event.preventDefault(); - cancelFolderEditing(event); - } - }} - onBlur={(event) => { - const nextFocus = event.relatedTarget; - if (!nextFocus || !event.currentTarget.parentElement?.contains(nextFocus)) { - cancelFolderEditing(); - } - }} - /> - - + event.stopPropagation(); + beginFolderEditing(folder); + }} + onKeyDown={(event) => { + if (!allowInlineFolderEdit) { + return; + } + if (event.key === 'Enter') { + event.preventDefault(); + event.stopPropagation(); + beginFolderEditing(folder); + } + }} + > + {folder.name} + + )} - ) : ( - { - if (!allowInlineFolderEdit) { - return; - } - event.preventDefault(); - event.stopPropagation(); - beginFolderEditing(folder); - }} - onKeyDown={(event) => { - if (!allowInlineFolderEdit) { - return; - } - if (event.key === 'Enter') { - event.preventDefault(); - event.stopPropagation(); - beginFolderEditing(folder); - } - }} - > - {folder.name} - - )} - - + +
+
+
+
- — - — ); } diff --git a/frontend/src/documents/panel/DocumentsPanel.jsx b/frontend/src/documents/panel/DocumentsPanel.jsx index a5d307b..5692736 100644 --- a/frontend/src/documents/panel/DocumentsPanel.jsx +++ b/frontend/src/documents/panel/DocumentsPanel.jsx @@ -196,7 +196,6 @@ const DocumentsPanel = ({ [handleDocumentPreviewZoom, onInspectDocument], ); - const selectedRowKeySet = useMemo(() => new Set(selectedEntries || []), [selectedEntries]); const navigableRows = useMemo( () => entries.map((entry) => ({ key: entry.key, type: entry.type, id: entry.id })), [entries], @@ -234,21 +233,12 @@ const DocumentsPanel = ({ } onFocusedRowChange?.(resolvedKey); - - if (!selectedRowKeySet.has(resolvedKey) && typeof onEntrySelection === 'function') { - onEntrySelection(resolvedKey, { - shiftKey: false, - preventDefault: () => {}, - }); - } }, [ focusedRowKey, navigableRowKeys, navigableRows, - onEntrySelection, onFocusedRowChange, selectedEntries, - selectedRowKeySet, ]); const handlePanelKeyDown = useCallback( diff --git a/frontend/src/documents/useEntryPointer.js b/frontend/src/documents/useEntryPointer.js index 826645f..4d5cb13 100644 --- a/frontend/src/documents/useEntryPointer.js +++ b/frontend/src/documents/useEntryPointer.js @@ -14,11 +14,15 @@ export const isPrimaryPointerEvent = (event) => { return type === 'click' || type === 'pointerdown' || type === 'pointerup'; }; +const EntryType = Object.freeze({ + document: 'document', + folder: 'folder', +}); + export const useEntryPointer = ({ resolveDocumentRowKey, resolveFolderRowKey, - onSelectDocument, - onSelectFolder, + onSelectEntry, onInspectDocument, }) => useCallback( @@ -28,41 +32,34 @@ export const useEntryPointer = ({ } const { type, id } = entry; - if (type !== 'document' && type !== 'folder') { + if (type !== EntryType.document && type !== EntryType.folder) { return; } const rowKey = entry.key - || (type === 'document' ? resolveDocumentRowKey?.(id) : resolveFolderRowKey?.(id)); + || (type === EntryType.document ? resolveDocumentRowKey?.(id) : resolveFolderRowKey?.(id)); if (!rowKey) { return; } const modifierClick = isPointerModifierEvent(event); const primaryClick = isPrimaryPointerEvent(event); - const metadata = { modifierClick, primaryClick, rowKey }; + const metadata = { modifierClick, primaryClick, rowKey, type, id }; - if (type === 'document') { - if (typeof onSelectDocument === 'function') { - onSelectDocument(id, event, metadata); - } - if (!modifierClick && primaryClick && typeof onInspectDocument === 'function') { - onInspectDocument(id, metadata); - } - return; + if (typeof onSelectEntry === 'function') { + onSelectEntry(entry, event, metadata); } - if (typeof onSelectFolder === 'function') { - onSelectFolder(id, event, metadata); + if ( + type === EntryType.document + && !modifierClick + && primaryClick + && typeof onInspectDocument === 'function' + ) { + onInspectDocument(id, metadata); } }, - [ - resolveDocumentRowKey, - resolveFolderRowKey, - onSelectDocument, - onSelectFolder, - onInspectDocument, - ], + [resolveDocumentRowKey, resolveFolderRowKey, onSelectEntry, onInspectDocument], ); export default useEntryPointer; diff --git a/frontend/src/hooks/documents/useDocumentDragHandlers.js b/frontend/src/hooks/documents/useDocumentDragHandlers.js index 9662e89..eaec276 100644 --- a/frontend/src/hooks/documents/useDocumentDragHandlers.js +++ b/frontend/src/hooks/documents/useDocumentDragHandlers.js @@ -29,6 +29,10 @@ const useDocumentDragHandlers = ({ ({ documents = [], folders = [] } = {}) => { destroyDragPreview(); + if (typeof document === 'undefined') { + return null; + } + const docEntries = (documents || []).filter(Boolean); const folderEntries = (folders || []).filter(Boolean); const totalCount = docEntries.length + folderEntries.length; @@ -54,6 +58,8 @@ const useDocumentDragHandlers = ({ const wrapper = document.createElement('div'); wrapper.className = 'document-drag-preview'; wrapper.style.setProperty('--drag-preview-size', `${canvasSize}px`); + wrapper.style.width = `${canvasSize}px`; + wrapper.style.height = `${canvasSize}px`; visibleItems.forEach((item, index) => { const layer = document.createElement('div'); @@ -101,15 +107,23 @@ const useDocumentDragHandlers = ({ layer.textContent = doc?.title || 'Document'; } } else { - const folderId = item.payload; - const rowEl = folderId ? document.getElementById(`folder-row-${folderId}`) : null; - const iconEl = rowEl?.querySelector('.thumb-icon'); + const payload = item.payload; + const folderId = typeof payload === 'string' ? payload : payload?.id; + const rowEl = folderId + ? document.getElementById(`folder-row-${folderId}`) + || document.getElementById(`folder-card-${folderId}`) + : null; + const iconEl = rowEl?.querySelector('.thumb-icon, .folder-card__icon'); layer.style.width = `${size}px`; layer.style.height = `${size}px`; + layer.classList.add('document-drag-preview__item--folder'); let content = null; if (iconEl instanceof HTMLElement) { - content = iconEl.cloneNode(true); + const cloneSource = iconEl.classList.contains('folder-card__icon') + ? iconEl.querySelector('svg') || iconEl + : iconEl; + content = cloneSource.cloneNode(true); content.classList.add('document-drag-preview__folder-thumb'); const svg = content.querySelector('svg'); if (svg) { @@ -276,11 +290,19 @@ const useDocumentDragHandlers = ({ console.warn('[documents] Failed to populate folder drag payload', error); } - const previewDocs = effectiveDocumentSelection - .map((id) => documentLookup.get(id) || null) - .filter(Boolean); - createDragPreview({ documents: previewDocs, folders: uniqueFolders }); + const previewNode = createDragPreview({ + documents: effectiveDocumentSelection + .map((id) => documentLookup.get(id) || null) + .filter(Boolean), + folders: uniqueFolders, + }); event.currentTarget.classList.add('dragging'); + + if (previewNode) { + const width = previewNode.offsetWidth || 96; + const height = previewNode.offsetHeight || 96; + event.dataTransfer.setDragImage(previewNode, width / 2, height / 2); + } }, [ selectedFolderIds, diff --git a/frontend/src/hooks/documents/useDocumentsWorkspace.js b/frontend/src/hooks/documents/useDocumentsWorkspace.js index f79dc09..f17a52c 100644 --- a/frontend/src/hooks/documents/useDocumentsWorkspace.js +++ b/frontend/src/hooks/documents/useDocumentsWorkspace.js @@ -50,6 +50,11 @@ import useDocumentDragHandlers from './useDocumentDragHandlers'; import useDocumentMutations from './useDocumentMutations'; import useDetailWorkspace from '../../detail/useDetailWorkspace'; +const EntryType = Object.freeze({ + document: 'document', + folder: 'folder', +}); + const noop = () => {}; const useDocumentsWorkspace = ({ @@ -1185,19 +1190,15 @@ const useDocumentsWorkspace = ({ const handleEntryPointerCore = useEntryPointerCore({ resolveDocumentRowKey, resolveFolderRowKey, - onSelectDocument: (documentId, event, { rowKey }) => { - const key = rowKey || resolveDocumentRowKey(documentId); + onSelectEntry: (entry, event, { rowKey, modifierClick, primaryClick }) => { + const { type, id } = entry; + const key = rowKey + || (type === EntryType.document ? resolveDocumentRowKey(id) : resolveFolderRowKey(id)); if (key) { handleEntrySelection(key, event); } - }, - onSelectFolder: (folderId, event, { modifierClick, primaryClick, rowKey }) => { - const key = rowKey || resolveFolderRowKey(folderId); - if (key) { - handleEntrySelection(key, event); - } - if (!modifierClick && primaryClick) { - selectFolder(folderId); + if (type === EntryType.folder && !modifierClick && primaryClick) { + selectFolder(id); } }, }); diff --git a/frontend/src/hooks/documents/useFolderTree.js b/frontend/src/hooks/documents/useFolderTree.js index ce5f369..b0f7675 100644 --- a/frontend/src/hooks/documents/useFolderTree.js +++ b/frontend/src/hooks/documents/useFolderTree.js @@ -85,9 +85,8 @@ const useFolderTree = ({ })(); setFocusedDocumentId(nextFocus); - selectionAnchorRef.current = nextDocKeys.length - ? nextDocKeys[nextDocKeys.length - 1] - : null; + const nextAnchor = mergedSelection.length ? mergedSelection[mergedSelection.length - 1] : null; + selectionAnchorRef.current = nextAnchor; selectionOrderRef.current = mergedSelection; setSelectionOrder(mergedSelection); }, diff --git a/frontend/src/styles/documents/drag-preview.css b/frontend/src/styles/documents/drag-preview.css new file mode 100644 index 0000000..ada971f --- /dev/null +++ b/frontend/src/styles/documents/drag-preview.css @@ -0,0 +1,76 @@ +.document-drag-preview { + position: fixed; + pointer-events: none; + top: -9999px; + left: -9999px; + width: var(--drag-preview-size, 96px); + height: var(--drag-preview-size, 96px); + z-index: 9999; +} + +.document-drag-preview__item { + position: absolute; + top: 50%; + left: 50%; + width: 64px; + height: 64px; + border-radius: 6px; + box-shadow: 0 6px 12px var(--shadow-pop); + overflow: hidden; + background-color: var(--overlay-dim); + display: flex; + align-items: center; + justify-content: center; + color: #fff; + font-weight: 600; + font-size: 0.8rem; + text-transform: uppercase; + transform: translate(-50%, -50%) rotate(var(--rotation-deg, 0deg)); + transform-origin: center; +} + +.document-drag-preview__item--folder { + background: transparent; + box-shadow: none; + border-radius: 0; +} + +.document-drag-preview__item--image { + background-color: #000; + background-repeat: no-repeat; + background-size: contain; + background-position: center; +} + +.document-drag-preview__item .document-thumbnail, +.document-drag-preview__item img { + width: 100%; + height: 100%; + object-fit: cover; + pointer-events: none; +} + +.document-drag-preview__item .thumb-placeholder, +.document-drag-preview__item .thumb-placeholder * { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; +} + +.document-drag-preview__folder-thumb { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; +} + +.document-drag-preview__folder-thumb svg { + width: 48px; + height: 48px; + color: var(--accent-strong, var(--accent)); +} diff --git a/frontend/src/styles/documents/listing.css b/frontend/src/styles/documents/listing.css index 751336e..9741eb5 100644 --- a/frontend/src/styles/documents/listing.css +++ b/frontend/src/styles/documents/listing.css @@ -13,8 +13,28 @@ min-height: 0; } -.folder-row.is-drop-target { - outline: 2px dashed var(--accent); + + +.documents-panel tr.folder.is-drop-target { + outline: 2px dashed var(--accent-strong, var(--accent)); + outline-offset: -2px; +} + +.folder-row__columns { + display: grid; + grid-template-columns: minmax(0, 1fr) 7rem 7rem; + gap: 0.5rem; + align-items: center; +} + +.folder-row__meta { + font-variant-numeric: tabular-nums; + color: var(--muted); + text-align: left; +} + +.documents-grid .folder-card.is-drop-target { + outline: 2px dashed var(--accent-strong, var(--accent)); outline-offset: 2px; } diff --git a/frontend/src/styles/documents/viewer.css b/frontend/src/styles/documents/viewer.css index c73de23..17e2e21 100644 --- a/frontend/src/styles/documents/viewer.css +++ b/frontend/src/styles/documents/viewer.css @@ -63,6 +63,12 @@ pointer-events: none; } +.document-drag-preview__item--folder { + background: transparent; + box-shadow: none; + border-radius: 0; +} + .document-drag-preview__folder-thumb { width: 100%; height: 100%; diff --git a/frontend/src/styles/index.css b/frontend/src/styles/index.css index 884e2fd..e313188 100644 --- a/frontend/src/styles/index.css +++ b/frontend/src/styles/index.css @@ -6,6 +6,7 @@ @import './documents/controls.css'; @import './layout/structure.css'; @import './documents/viewer.css'; +@import './documents/drag-preview.css'; @import './documents/tags-correspondents.css'; @import './documents/panel-sections.css'; @import './sidebar/sidebar.css'; diff --git a/frontend/src/styles/sidebar/sidebar.css b/frontend/src/styles/sidebar/sidebar.css index fdb64a4..a1a8479 100644 --- a/frontend/src/styles/sidebar/sidebar.css +++ b/frontend/src/styles/sidebar/sidebar.css @@ -23,6 +23,11 @@ -webkit-user-select: none; } +.sidebar .folder-row.is-drop-target { + outline: 2px dashed var(--accent-strong, var(--accent)); + outline-offset: 2px; +} + .folder-row .name-wrap { display: inline-flex; align-items: center; From 26798ac430bcf4d5adead10bed56f62efa630e15 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Tue, 11 Nov 2025 00:48:13 +0100 Subject: [PATCH 07/13] fix --- frontend/src/hooks/documents/useDocumentDragHandlers.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/hooks/documents/useDocumentDragHandlers.js b/frontend/src/hooks/documents/useDocumentDragHandlers.js index eaec276..b131e6d 100644 --- a/frontend/src/hooks/documents/useDocumentDragHandlers.js +++ b/frontend/src/hooks/documents/useDocumentDragHandlers.js @@ -177,7 +177,7 @@ const useDocumentDragHandlers = ({ : isGridView ? [...selectedDocumentIds, documentId] : [documentId]; - const folderSelection = selectedFolderIds.length ? [...selectedFolderIds] : []; + const folderSelection = []; if (!isAlreadySelected && !isGridView) { applySelection([documentKey], { @@ -223,7 +223,6 @@ const useDocumentDragHandlers = ({ }, [ selectedDocumentIds, - selectedFolderIds, applySelection, documentLookup, createDragPreview, From 3fe325c4ceb04f066c895d4d80d05795b8fe3ca6 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Tue, 11 Nov 2025 01:57:00 +0100 Subject: [PATCH 08/13] fix --- frontend/src/documents/DocumentsList.jsx | 168 +++++++++++----------- frontend/src/styles/documents/listing.css | 13 -- 2 files changed, 82 insertions(+), 99 deletions(-) diff --git a/frontend/src/documents/DocumentsList.jsx b/frontend/src/documents/DocumentsList.jsx index d17fdce..714b2d8 100644 --- a/frontend/src/documents/DocumentsList.jsx +++ b/frontend/src/documents/DocumentsList.jsx @@ -139,96 +139,92 @@ const DocumentsList = ({
- -
-
-
- - - {isFolderEditing ? ( - - setFolderDraft(event.target.value)} - onClick={(event) => event.stopPropagation()} - onKeyDown={(event) => { - if (event.key === 'Enter') { - event.preventDefault(); - submitFolderEditing(folder); - } else if (event.key === 'Escape') { - event.preventDefault(); - cancelFolderEditing(event); - } - }} - onBlur={(event) => { - const nextFocus = event.relatedTarget; - if (!nextFocus || !event.currentTarget.parentElement?.contains(nextFocus)) { - cancelFolderEditing(); - } - }} - /> - - - - ) : ( - { - if (!allowInlineFolderEdit) { - return; - } + +
+ + + {isFolderEditing ? ( + + setFolderDraft(event.target.value)} + onClick={(event) => event.stopPropagation()} + onKeyDown={(event) => { + if (event.key === 'Enter') { event.preventDefault(); - event.stopPropagation(); - beginFolderEditing(folder); - }} - onKeyDown={(event) => { - if (!allowInlineFolderEdit) { - return; - } - if (event.key === 'Enter') { - event.preventDefault(); - event.stopPropagation(); - beginFolderEditing(folder); - } - }} - > - {folder.name} - - )} + submitFolderEditing(folder); + } else if (event.key === 'Escape') { + event.preventDefault(); + cancelFolderEditing(event); + } + }} + onBlur={(event) => { + const nextFocus = event.relatedTarget; + if (!nextFocus || !event.currentTarget.parentElement?.contains(nextFocus)) { + cancelFolderEditing(); + } + }} + /> + + - -
-
-
-
+ ) : ( + { + if (!allowInlineFolderEdit) { + return; + } + event.preventDefault(); + event.stopPropagation(); + beginFolderEditing(folder); + }} + onKeyDown={(event) => { + if (!allowInlineFolderEdit) { + return; + } + if (event.key === 'Enter') { + event.preventDefault(); + event.stopPropagation(); + beginFolderEditing(folder); + } + }} + > + {folder.name} + + )} + +
+ — + — ); } diff --git a/frontend/src/styles/documents/listing.css b/frontend/src/styles/documents/listing.css index 9741eb5..c7a0fc1 100644 --- a/frontend/src/styles/documents/listing.css +++ b/frontend/src/styles/documents/listing.css @@ -20,19 +20,6 @@ outline-offset: -2px; } -.folder-row__columns { - display: grid; - grid-template-columns: minmax(0, 1fr) 7rem 7rem; - gap: 0.5rem; - align-items: center; -} - -.folder-row__meta { - font-variant-numeric: tabular-nums; - color: var(--muted); - text-align: left; -} - .documents-grid .folder-card.is-drop-target { outline: 2px dashed var(--accent-strong, var(--accent)); outline-offset: 2px; From 6ae497323ec683046e6722ce997bc83a5f4d9eea Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Tue, 11 Nov 2025 10:09:15 +0100 Subject: [PATCH 09/13] viewer --- frontend/src/app/useWorkspaceSurface.js | 2 - frontend/src/preview/DocumentViewerPanel.jsx | 163 ++++++++++++++++--- frontend/src/styles/documents/viewer.css | 46 +++++- 3 files changed, 182 insertions(+), 29 deletions(-) diff --git a/frontend/src/app/useWorkspaceSurface.js b/frontend/src/app/useWorkspaceSurface.js index 81fcb80..bb5d513 100644 --- a/frontend/src/app/useWorkspaceSurface.js +++ b/frontend/src/app/useWorkspaceSurface.js @@ -83,7 +83,6 @@ export const useWorkspaceSurface = ({ onFolderNavigate, } = detailExtras; return createDocumentViewerSurface({ - documentId: previewDocumentId, document: previewWorkspaceDocument, previewEntry: previewWorkspaceEntry, ensureAssetUrl, @@ -108,7 +107,6 @@ export const useWorkspaceSurface = ({ }, [ showPreviewWorkspace, previewWorkspaceDocument, - previewDocumentId, previewWorkspaceEntry, ensureAssetUrl, ensurePreviewData, diff --git a/frontend/src/preview/DocumentViewerPanel.jsx b/frontend/src/preview/DocumentViewerPanel.jsx index 245aee6..2c8cf73 100644 --- a/frontend/src/preview/DocumentViewerPanel.jsx +++ b/frontend/src/preview/DocumentViewerPanel.jsx @@ -1,4 +1,11 @@ -import React, { useCallback, useMemo } from 'react'; +import React, { + useCallback, + useEffect, + useLayoutEffect, + useMemo, + useRef, + useState, +} from 'react'; import { DownloadIcon, CloseIcon } from '../ui/icons'; import { buildCorrespondentOptions, @@ -9,10 +16,50 @@ import { extractDocumentMetadataPayload } from '../documents/documentMetadata'; import { createDocumentActionState } from '../documents/documentActions'; import { resolveDocumentAssetUrl } from '../asset_manager'; +const PORTRAIT_WIDTH_TO_HEIGHT = 1 / Math.sqrt(2); // ≈0.707 (A-series aspect ratio) +const DOCUMENT_VIEWER_PORTRAIT_HEIGHT_RATIO = 0.6; +const PORTRAIT_RATIO_STYLE_ID = 'document-viewer-portrait-ratio-style'; + +const ensurePortraitRatioStyle = () => { + if (typeof document === 'undefined') { + return; + } + + const cssValue = String(DOCUMENT_VIEWER_PORTRAIT_HEIGHT_RATIO); + const cssText = `:root { --document-viewer-portrait-height-ratio: ${cssValue}; }`; + + let styleEl = document.getElementById(PORTRAIT_RATIO_STYLE_ID); + if (!styleEl) { + styleEl = document.createElement('style'); + styleEl.id = PORTRAIT_RATIO_STYLE_ID; + document.head.appendChild(styleEl); + } + + if (styleEl.textContent !== cssText) { + styleEl.textContent = cssText; + } +}; + +if (typeof document !== 'undefined') { + ensurePortraitRatioStyle(); +} + +const computeStackedLayoutBreakpoint = () => { + const viewportHeight = typeof window !== 'undefined' ? window.innerHeight : 900; + const portraitViewportWidth = viewportHeight + * DOCUMENT_VIEWER_PORTRAIT_HEIGHT_RATIO + * PORTRAIT_WIDTH_TO_HEIGHT; + const detailsColumnWidth = 320; // px ~ 20rem for metadata & tabs + const gutterAllowance = 48; // padding + grid gap + + const desiredWidth = portraitViewportWidth + detailsColumnWidth + gutterAllowance; + return desiredWidth; +}; + const DocumentViewerPanel = ({ document, - documentId, previewEntry, + hydrateDocument, tagLookupById, tagOptions, onTagAdd, @@ -182,13 +229,81 @@ const DocumentViewerPanel = ({ [hasOcr, loadOcrContent], ); + const viewerRef = useRef(null); + const [isStackedLayout, setIsStackedLayout] = useState(false); + + useEffect(() => { + if (typeof hydrateDocument === 'function' && document?.id) { + hydrateDocument(document.id); + } + }, [hydrateDocument, document?.id]); + + useLayoutEffect(() => { + ensurePortraitRatioStyle(); + }, []); + + useLayoutEffect(() => { + const node = viewerRef.current; + if (!node) { + setIsStackedLayout(false); + return undefined; + } + + let frame = null; + const commitMeasure = (width) => { + if (frame) { + cancelAnimationFrame(frame); + } + frame = requestAnimationFrame(() => { + const breakpoint = computeStackedLayoutBreakpoint(); + setIsStackedLayout(width < breakpoint); + }); + }; + + const measure = () => { + commitMeasure(node.getBoundingClientRect().width); + }; + + measure(); + + if (typeof ResizeObserver === 'undefined') { + window.addEventListener('resize', measure); + return () => { + if (frame) { + cancelAnimationFrame(frame); + } + window.removeEventListener('resize', measure); + }; + } + + const observer = new ResizeObserver((entries) => { + if (!entries.length) { + return; + } + commitMeasure(entries[0].contentRect.width); + }); + + observer.observe(node); + + return () => { + observer.disconnect(); + if (frame) { + cancelAnimationFrame(frame); + } + }; + }, [document?.id]); + + const viewerClassName = isStackedLayout + ? 'document-viewer document-viewer--stacked' + : 'document-viewer'; + if (!document) { return ( -
+
- Loading document{documentId ? ` ${documentId}` : ''}… + Loading document…
@@ -200,7 +315,7 @@ const DocumentViewerPanel = ({ } return ( -
+
{ - if (!document || !actionState) { + if (!document) { return null; } - const { downloadHref } = actionState; + const downloadHref = actionState?.downloadHref || previewEntry?.url; + if (!downloadHref) { + return null; + } return ( <> @@ -257,7 +376,6 @@ export const createDocumentViewerHeaderActions = ({ }; export const createDocumentViewerSurface = ({ - documentId, document, previewEntry, ensureAssetUrl, @@ -278,11 +396,11 @@ export const createDocumentViewerSurface = ({ onUpdateIssued, resolveFolderPath, }) => { - if (!documentId && !document) { + if (!document) { return null; } - const title = document?.title || 'Document preview'; + const title = document.title || 'Document preview'; const closeButton = onClose ? ( - -
- ) : null} -
- ); -}; +import { extractDocumentMetadataPayload } from '../documents/documentMetadata'; +import DocumentViewerLayout from '../preview/DocumentViewerLayout'; const DetailPanel = ({ document = null, @@ -126,7 +20,6 @@ const DetailPanel = ({ onTagAdd, onTagRemove, onOpenPreview, - onPromoteSelection, onUpdateTitle = async () => false, onUpdateIssued = async () => false, ensureAssetUrl = null, @@ -138,11 +31,10 @@ const DetailPanel = ({ resolveApiPath, onFolderNavigate = null, resolveFolderPath = null, + previewEntry = null, onClose = () => {}, }) => { const singleDoc = document || null; - const singleDocId = singleDoc?.id || null; - const selectionKey = singleDocId || 'none'; const { downloadHref: singleDownloadHref } = useMemo( () => @@ -192,81 +84,6 @@ const DetailPanel = ({ ]; }, [singleDoc, resolveFolderPath, detailSummary, onFolderNavigate]); - const [zoomedPreview, setZoomedPreview] = useState(null); - - useEffect(() => { - setZoomedPreview(null); - }, [selectionKey]); - - const handlePreviewActivate = useCallback( - (docId) => { - if (!docId) return; - onPromoteSelection?.(docId); - }, - [onPromoteSelection], - ); - - const singlePreviewNavigator = useAssetNavigator({ - document: singleDoc, - assetType: 'preview', - ensureAssetUrl, - getAsset: getDocumentAsset, - prefetch: 3, - }); - - const makePreviewItem = useCallback( - (doc, ordinal = 1) => { - if (!doc) return null; - const asset = getDocumentAsset(doc, 'preview'); - const assetView = createAssetView(asset); - const object = assetView.getObject(ordinal); - let url = object?.url || null; - if (!url) { - url = resolveDocumentAssetUrl(doc, 'preview', { - ensureAssetUrl, - getAsset: getDocumentAsset, - ensureOptions: { start: ordinal, limit: 1 }, - objectOrdinal: ordinal, - }); - } - if (!url) { - return null; - } - const metadata = object?.metadata || assetView.getPrimaryMetadata() || {}; - const orientation = derivePreviewOrientation(metadata); - return { - id: doc.id, - url, - orientation, - alt: doc.title, - }; - }, - [ensureAssetUrl, getDocumentAsset], - ); - - const singlePreviewItem = useMemo(() => { - if (!singleDoc) return null; - const url = singlePreviewNavigator.currentUrl; - if (url) { - return { - id: singleDoc.id, - url, - orientation: derivePreviewOrientation(singlePreviewNavigator.currentMetadata), - alt: singleDoc.title, - }; - } - return makePreviewItem(singleDoc, 1); - }, [ - singleDoc, - singlePreviewNavigator.currentUrl, - singlePreviewNavigator.currentMetadata, - makePreviewItem, - ]); - - const singleCardinality = singlePreviewNavigator.cardinality; - const singleEffectiveCardinality = singleCardinality || (singlePreviewNavigator.currentUrl ? 1 : 0); - const singleHasPreview = Boolean(singlePreviewNavigator.currentUrl); - const correspondentOptions = useMemo( () => buildCorrespondentOptions(Array.isArray(correspondents) ? correspondents : []), [correspondents], @@ -277,6 +94,12 @@ const DetailPanel = ({ return sortCorrespondents(singleDoc.correspondents || []); }, [singleDoc]); + useEffect(() => { + if (typeof ensurePreviewData === 'function' && singleDoc?.id) { + ensurePreviewData(singleDoc.id); + } + }, [ensurePreviewData, singleDoc?.id]); + const singleSummaryProps = useMemo( () => ({ tagLookupById, @@ -304,6 +127,11 @@ const DetailPanel = ({ ], ); + const singleMetadataPayload = useMemo( + () => extractDocumentMetadataPayload(singleDoc), + [singleDoc], + ); + const singleHasOcr = useMemo(() => { if (!singleDoc || typeof getDocumentAsset !== 'function') { return false; @@ -365,183 +193,22 @@ const DetailPanel = ({ [singleHasOcr, loadSingleOcrContent], ); - const openZoomPreview = useCallback((docId) => { - if (!docId) return; - setZoomedPreview({ docId }); - }, []); - - const closeZoomPreview = useCallback(() => { - setZoomedPreview(null); - }, []); - - const handleSingleZoom = useCallback( - (entry) => { - if (!singleHasPreview) return; - const targetId = entry?.id ?? singleDocId; - if (!targetId) return; - openZoomPreview(targetId); - }, - [openZoomPreview, singleHasPreview, singleDocId], - ); - - const zoomDisplay = useMemo(() => { - if ( - !zoomedPreview - || !singleDoc - || !singleDocId - || zoomedPreview.docId !== singleDocId - || !singleHasPreview - ) { - return null; - } - - return { - url: singlePreviewNavigator.currentUrl, - alt: singleDoc.title, - canGoPrev: - singleEffectiveCardinality > 1 && Boolean(singlePreviewNavigator.canGoPrev), - canGoNext: - singleEffectiveCardinality > 1 && Boolean(singlePreviewNavigator.canGoNext), - goPrev: singlePreviewNavigator.goPrev, - goNext: singlePreviewNavigator.goNext, - }; - }, [ - zoomedPreview, - singleDoc, - singleDocId, - singleHasPreview, - singlePreviewNavigator.currentUrl, - singlePreviewNavigator.canGoPrev, - singlePreviewNavigator.canGoNext, - singlePreviewNavigator.goPrev, - singlePreviewNavigator.goNext, - singleEffectiveCardinality, - ]); - - useEffect(() => { - if (zoomedPreview && !zoomDisplay) { - setZoomedPreview(null); - } - }, [zoomedPreview, zoomDisplay]); - - const { - documentId: singleNavigatorDocId, - asset: singleNavigatorAsset, - ordinal: singleNavigatorOrdinal, - canGoPrev: singleNavigatorCanGoPrev, - canGoNext: singleNavigatorCanGoNext, - cardinality: singleNavigatorCardinality, - } = singlePreviewNavigator; - - useEffect(() => { - if (typeof ensureAssetUrl !== 'function') { - return; - } - if (!singleNavigatorDocId || !singleNavigatorAsset || !Number.isFinite(singleNavigatorOrdinal)) { - return; - } - - const requests = []; - if (singleNavigatorCanGoPrev) { - const prevOrdinal = Math.max(1, singleNavigatorOrdinal - 1); - if (!singleNavigatorCardinality || prevOrdinal <= singleNavigatorCardinality) { - requests.push( - ensureAssetUrl(singleNavigatorDocId, singleNavigatorAsset, { - start: prevOrdinal, - limit: 1, - objectOrdinal: prevOrdinal, - }), - ); - } - } - if (singleNavigatorCanGoNext) { - const nextOrdinal = singleNavigatorOrdinal + 1; - if (!singleNavigatorCardinality || nextOrdinal <= singleNavigatorCardinality) { - requests.push( - ensureAssetUrl(singleNavigatorDocId, singleNavigatorAsset, { - start: nextOrdinal, - limit: 1, - objectOrdinal: nextOrdinal, - }), - ); - } - } - - requests.forEach((promise) => promise?.catch?.(() => {})); - }, [ - ensureAssetUrl, - singleNavigatorDocId, - singleNavigatorAsset, - singleNavigatorOrdinal, - singleNavigatorCanGoPrev, - singleNavigatorCanGoNext, - singleNavigatorCardinality, - ]); - const renderContent = () => { if (!singleDoc) { return

Select a document to view metadata, tags and actions.

; } - const effectiveCardinality = singleEffectiveCardinality; - const navCanGoPrev = Boolean(singlePreviewNavigator.canGoPrev); - const navCanGoNext = Boolean(singlePreviewNavigator.canGoNext); - const hasPreviewImage = Boolean(singlePreviewNavigator.currentUrl); - const previewMissingAsset = !singlePreviewNavigator.currentUrl; - const displayContentType = singleDoc.content_type || 'this file type'; - const displayFilename = - singleDoc.filename || singleDoc.original_name || singleDoc.title || 'download'; - const previewFallback = previewMissingAsset ? ( -
-
- Preview not available for {displayContentType} files. -
-
{displayFilename}
- {singleDownloadHref ? ( - - - Download - - ) : null} -
- ) : null; - const emptyMessage = previewMissingAsset ? 'Preview unavailable' : 'Preview loading…'; - const showNav = hasPreviewImage && (effectiveCardinality > 1 || navCanGoPrev || navCanGoNext); - return ( -
-
- -
-
- -
-
+
+ +
); }; @@ -598,37 +265,26 @@ const DetailPanel = ({ } return ( - <> - - {singleDoc && ( - - )} - + ); }; diff --git a/frontend/src/detail/useDetailWorkspace.js b/frontend/src/detail/useDetailWorkspace.js index 4c74455..27859c6 100644 --- a/frontend/src/detail/useDetailWorkspace.js +++ b/frontend/src/detail/useDetailWorkspace.js @@ -22,7 +22,6 @@ const useDetailWorkspace = ({ previewDocumentId, activePreviewId, openDocumentPreview, - promoteSelectionOrder, handleDocumentTitleUpdate, handleDocumentIssuedUpdate, handleDocumentTagAdd, @@ -242,7 +241,6 @@ const useDetailWorkspace = ({ onTagRemove: handleTagRemove, previewEntry: selectedPreviewEntry, onOpenPreview: openDocumentPreview, - onPromoteSelection: promoteSelectionOrder, activePreviewId, onUpdateTitle: handleDocumentTitleUpdate, onUpdateIssued: handleDocumentIssuedUpdate, @@ -272,7 +270,6 @@ const useDetailWorkspace = ({ handleDocumentTitleUpdate, handleTagRemove, openDocumentPreview, - promoteSelectionOrder, resolveApiPath, resolveFolderPath, selectFolder, diff --git a/frontend/src/preview/DocumentViewerLayout.jsx b/frontend/src/preview/DocumentViewerLayout.jsx new file mode 100644 index 0000000..964e5ea --- /dev/null +++ b/frontend/src/preview/DocumentViewerLayout.jsx @@ -0,0 +1,105 @@ +import React, { useMemo } from 'react'; +import DocumentInfoPanel from '../documents/DocumentInfoPanel'; +import { DownloadIcon } from '../ui/icons'; + +const DocumentViewerLayout = ({ + document, + previewEntry, + summaryProps, + metadataPayload, + contentTabConfig, + resetKey, + classNamePrefix = 'document-viewer', + defaultTabId = 'details', + infoPanelProps = {}, + previewLoadingMessage = 'Preparing preview…', +}) => { + const previewContent = useMemo(() => { + if (!document || !previewEntry?.url) { + return null; + } + + const normalizedContentType = (previewEntry.contentType + || document.content_type + || '') + .toLowerCase(); + const isImage = normalizedContentType.startsWith('image/'); + const isPdf = normalizedContentType === 'application/pdf' + || normalizedContentType === 'application/x-pdf'; + + if (isImage) { + return ( + {`Preview + ); + } + + if (isPdf) { + return ( +