Compare commits

...

6 Commits

Author SHA1 Message Date
Ivan
4113370c62 Merge branch 'main' of http://dev.concept.ru:3000/ConceptProd/Portal
Some checks failed
Frontend CI / build (22.x) (push) Has been cancelled
2025-02-19 19:32:37 +03:00
Ivan
be1edcd949 F: Add query invalidation after error in mutation 2025-02-19 19:25:11 +03:00
Ivan
8c0d5bfca7 F: Add global mutation error fallback 2025-02-19 19:15:57 +03:00
Ivan
14276d661c F: viewTransition to navigation 2025-02-19 19:15:02 +03:00
Ivan
ea2ec6aa8a npm update 2025-02-19 00:58:54 +03:00
Ivan
cf3db3aa72 F: Implement schema checks for backend + small fixes 2025-02-18 23:56:44 +03:00
59 changed files with 419 additions and 302 deletions

View File

@ -11,8 +11,8 @@
"@dagrejs/dagre": "^1.1.4", "@dagrejs/dagre": "^1.1.4",
"@hookform/resolvers": "^4.1.0", "@hookform/resolvers": "^4.1.0",
"@lezer/lr": "^1.4.2", "@lezer/lr": "^1.4.2",
"@tanstack/react-query": "^5.66.0", "@tanstack/react-query": "^5.66.7",
"@tanstack/react-query-devtools": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.7",
"@tanstack/react-table": "^8.21.2", "@tanstack/react-table": "^8.21.2",
"@uiw/codemirror-themes": "^4.23.8", "@uiw/codemirror-themes": "^4.23.8",
"@uiw/react-codemirror": "^4.23.8", "@uiw/react-codemirror": "^4.23.8",
@ -27,7 +27,7 @@
"react-hook-form": "^7.54.2", "react-hook-form": "^7.54.2",
"react-icons": "^5.4.0", "react-icons": "^5.4.0",
"react-intl": "^7.1.6", "react-intl": "^7.1.6",
"react-router": "^7.1.5", "react-router": "^7.2.0",
"react-select": "^5.10.0", "react-select": "^5.10.0",
"react-tabs": "^6.1.0", "react-tabs": "^6.1.0",
"react-toastify": "^11.0.3", "react-toastify": "^11.0.3",
@ -43,8 +43,8 @@
"@playwright/test": "^1.50.1", "@playwright/test": "^1.50.1",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^22.13.4", "@types/node": "^22.13.4",
"@types/react": "^19.0.8", "@types/react": "^19.0.10",
"@types/react-dom": "^19.0.3", "@types/react-dom": "^19.0.4",
"@typescript-eslint/eslint-plugin": "^8.0.1", "@typescript-eslint/eslint-plugin": "^8.0.1",
"@typescript-eslint/parser": "^8.0.1", "@typescript-eslint/parser": "^8.0.1",
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
@ -62,7 +62,7 @@
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"ts-jest": "^29.2.5", "ts-jest": "^29.2.5",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"typescript-eslint": "^8.24.0", "typescript-eslint": "^8.24.1",
"vite": "^6.1.0" "vite": "^6.1.0"
} }
}, },
@ -847,9 +847,9 @@
} }
}, },
"node_modules/@codemirror/view": { "node_modules/@codemirror/view": {
"version": "6.36.2", "version": "6.36.3",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.2.tgz", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.3.tgz",
"integrity": "sha512-DZ6ONbs8qdJK0fdN7AB82CgI6tYXf4HWk1wSVa0+9bhVznCuuvhQtX8bFBoy3dv8rZSQqUd8GvhVAcielcidrA==", "integrity": "sha512-N2bilM47QWC8Hnx0rMdDxO2x2ImJ1FvZWXubwKgjeoOrWwEiFrtpA7SFHcuZ+o2Ze2VzbkgbzWVj4+V18LVkeg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@codemirror/state": "^6.5.0", "@codemirror/state": "^6.5.0",
@ -1592,32 +1592,19 @@
} }
}, },
"node_modules/@eslint/plugin-kit": { "node_modules/@eslint/plugin-kit": {
"version": "0.2.5", "version": "0.2.6",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.6.tgz",
"integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", "integrity": "sha512-+0TjwR1eAUdZtvv/ir1mGX+v0tUoR3VEPB8Up0LLJC+whRW0GgBBtpbOkg/a/U4Dxa6l5a3l9AJ1aWIQVyoWJA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@eslint/core": "^0.10.0", "@eslint/core": "^0.11.0",
"levn": "^0.4.1" "levn": "^0.4.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
"integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
"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/@floating-ui/core": { "node_modules/@floating-ui/core": {
"version": "1.6.9", "version": "1.6.9",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz",
@ -2733,9 +2720,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz",
"integrity": "sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==", "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -2747,9 +2734,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz",
"integrity": "sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg==", "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2761,9 +2748,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz",
"integrity": "sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA==", "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2775,9 +2762,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz",
"integrity": "sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA==", "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2789,9 +2776,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz",
"integrity": "sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA==", "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2803,9 +2790,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz",
"integrity": "sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q==", "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2817,9 +2804,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz",
"integrity": "sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==", "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -2831,9 +2818,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz",
"integrity": "sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==", "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -2845,9 +2832,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz",
"integrity": "sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==", "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2859,9 +2846,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz",
"integrity": "sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==", "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2873,9 +2860,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loongarch64-gnu": { "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz",
"integrity": "sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==", "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@ -2887,9 +2874,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz",
"integrity": "sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==", "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -2901,9 +2888,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz",
"integrity": "sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==", "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -2915,9 +2902,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz",
"integrity": "sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==", "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -2929,9 +2916,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz",
"integrity": "sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==", "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2943,9 +2930,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz",
"integrity": "sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==", "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -2957,9 +2944,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz",
"integrity": "sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==", "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -2971,9 +2958,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz",
"integrity": "sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg==", "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -2985,9 +2972,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.7.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz",
"integrity": "sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w==", "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -3033,9 +3020,9 @@
} }
}, },
"node_modules/@tanstack/query-core": { "node_modules/@tanstack/query-core": {
"version": "5.66.0", "version": "5.66.4",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.66.0.tgz", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.66.4.tgz",
"integrity": "sha512-J+JeBtthiKxrpzUu7rfIPDzhscXF2p5zE/hVdrqkACBP8Yu0M96mwJ5m/8cPPYQE9aRNvXztXHlNwIh4FEeMZw==", "integrity": "sha512-skM/gzNX4shPkqmdTCSoHtJAPMTtmIJNS0hE+xwTTUVYwezArCT34NMermABmBVUg5Ls5aiUXEDXfqwR1oVkcA==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"type": "github", "type": "github",
@ -3053,12 +3040,12 @@
} }
}, },
"node_modules/@tanstack/react-query": { "node_modules/@tanstack/react-query": {
"version": "5.66.0", "version": "5.66.7",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.66.0.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.66.7.tgz",
"integrity": "sha512-z3sYixFQJe8hndFnXgWu7C79ctL+pI0KAelYyW+khaNJ1m22lWrhJU2QrsTcRKMuVPtoZvfBYrTStIdKo+x0Xw==", "integrity": "sha512-qd3q/tUpF2K1xItfPZddk1k/8pSXnovg41XyCqJgPoyYEirMBtB0sVEVVQ/CsAOngzgWtBPXimVf4q4kM9uO6A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/query-core": "5.66.0" "@tanstack/query-core": "5.66.4"
}, },
"funding": { "funding": {
"type": "github", "type": "github",
@ -3069,9 +3056,9 @@
} }
}, },
"node_modules/@tanstack/react-query-devtools": { "node_modules/@tanstack/react-query-devtools": {
"version": "5.66.0", "version": "5.66.7",
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.66.0.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.66.7.tgz",
"integrity": "sha512-uB57wA2YZaQ2fPcFW0E9O1zAGDGSbRKRx84uMk/86VyU9jWVxvJ3Uzp+zNm+nZJYsuekCIo2opTdgNuvM3cKgA==", "integrity": "sha512-40z4PPkz06tYIF0vwLZZIZfZxKUH4OAaBOR14blCFyYm6hlU6qc+M82mkZ+D00HcEMhV7P4XeJiEuDhFq0q9Qw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/query-devtools": "5.65.0" "@tanstack/query-devtools": "5.65.0"
@ -3081,7 +3068,7 @@
"url": "https://github.com/sponsors/tannerlinsley" "url": "https://github.com/sponsors/tannerlinsley"
}, },
"peerDependencies": { "peerDependencies": {
"@tanstack/react-query": "^5.66.0", "@tanstack/react-query": "^5.66.7",
"react": "^18 || ^19" "react": "^18 || ^19"
} }
}, },
@ -3524,18 +3511,18 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.0.8", "version": "19.0.10",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.8.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz",
"integrity": "sha512-9P/o1IGdfmQxrujGbIMDyYaaCykhLKc0NGCtYcECNUr9UAaDe4gwvV9bR6tvd5Br1SG0j+PBpbKr2UYY8CwqSw==", "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"node_modules/@types/react-dom": { "node_modules/@types/react-dom": {
"version": "19.0.3", "version": "19.0.4",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz",
"integrity": "sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==", "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
@ -3576,17 +3563,17 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz",
"integrity": "sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ==", "integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.24.0", "@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/type-utils": "8.24.0", "@typescript-eslint/type-utils": "8.24.1",
"@typescript-eslint/utils": "8.24.0", "@typescript-eslint/utils": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.0", "@typescript-eslint/visitor-keys": "8.24.1",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.3.1", "ignore": "^5.3.1",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@ -3606,16 +3593,16 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz",
"integrity": "sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==", "integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.24.0", "@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/types": "8.24.0", "@typescript-eslint/types": "8.24.1",
"@typescript-eslint/typescript-estree": "8.24.0", "@typescript-eslint/typescript-estree": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.0", "@typescript-eslint/visitor-keys": "8.24.1",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@ -3631,14 +3618,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz",
"integrity": "sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==", "integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.24.0", "@typescript-eslint/types": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.0" "@typescript-eslint/visitor-keys": "8.24.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -3649,14 +3636,14 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz",
"integrity": "sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==", "integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "8.24.0", "@typescript-eslint/typescript-estree": "8.24.1",
"@typescript-eslint/utils": "8.24.0", "@typescript-eslint/utils": "8.24.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^2.0.1" "ts-api-utils": "^2.0.1"
}, },
@ -3673,9 +3660,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz",
"integrity": "sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==", "integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -3687,14 +3674,14 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz",
"integrity": "sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==", "integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.24.0", "@typescript-eslint/types": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.0", "@typescript-eslint/visitor-keys": "8.24.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -3714,16 +3701,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz",
"integrity": "sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==", "integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.24.0", "@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/types": "8.24.0", "@typescript-eslint/types": "8.24.1",
"@typescript-eslint/typescript-estree": "8.24.0" "@typescript-eslint/typescript-estree": "8.24.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -3738,13 +3725,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz",
"integrity": "sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==", "integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.24.0", "@typescript-eslint/types": "8.24.1",
"eslint-visitor-keys": "^4.2.0" "eslint-visitor-keys": "^4.2.0"
}, },
"engines": { "engines": {
@ -4320,9 +4307,9 @@
} }
}, },
"node_modules/babel-plugin-react-compiler": { "node_modules/babel-plugin-react-compiler": {
"version": "19.0.0-beta-30d8a17-20250209", "version": "19.0.0-beta-e552027-20250112",
"resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-30d8a17-20250209.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-e552027-20250112.tgz",
"integrity": "sha512-0pQHlz5nmBiEQ8ZWWVLeaBzz/FkToAdXEXBBnd21uSrDtIzhSe+s3VMvqMsv6vYHNTr+0KmsvVfEqXQp0W0kzg==", "integrity": "sha512-pUTT0mAZ4XLewC6bvqVeX015nVRLVultcSQlkzGdC10G6YV6K2h4E7cwGlLAuLKWTj3Z08mTO9uTnPP/opUBsg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -4558,9 +4545,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001699", "version": "1.0.30001700",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz",
"integrity": "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==", "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -5240,9 +5227,9 @@
} }
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.101", "version": "1.5.102",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.101.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz",
"integrity": "sha512-L0ISiQrP/56Acgu4/i/kfPwWSgrzYZUnQrC0+QPFuhqlLP1Ir7qzPPDVS9BcKIyWTRU8+o6CC8dKw38tSWhYIA==", "integrity": "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -5730,9 +5717,9 @@
} }
}, },
"node_modules/eslint-plugin-react-compiler": { "node_modules/eslint-plugin-react-compiler": {
"version": "19.0.0-beta-30d8a17-20250209", "version": "19.0.0-beta-e552027-20250112",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-30d8a17-20250209.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-e552027-20250112.tgz",
"integrity": "sha512-D2wohyvsW27KSQV8IhyjL9UhYKs4f7Y8WPIuNOeiYylOaredvb2vW/AAE2m36BWLsn3Q9xRYz1UZj2AXR15w/g==", "integrity": "sha512-VjkIXHouCYyJHgk5HmZ1LH+fAK5CX+ULRX9iNYtwYJ+ljbivFhIT+JJyxNT/USQpCeS2Dt5ahjFeeMv0RRwTww==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -6191,9 +6178,9 @@
} }
}, },
"node_modules/flatted": { "node_modules/flatted": {
"version": "3.3.2", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -9333,9 +9320,9 @@
} }
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "7.1.5", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.5.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.2.0.tgz",
"integrity": "sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA==", "integrity": "sha512-fXyqzPgCPZbqhrk7k3hPcCpYIlQ2ugIXDboHUzhJISFVy2DEPsmHgN588MyGmkIOv3jDgNfUE3kJi83L28s/LQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/cookie": "^0.6.0", "@types/cookie": "^0.6.0",
@ -9622,9 +9609,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.34.7", "version": "4.34.8",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.7.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz",
"integrity": "sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ==", "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -9638,25 +9625,25 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.34.7", "@rollup/rollup-android-arm-eabi": "4.34.8",
"@rollup/rollup-android-arm64": "4.34.7", "@rollup/rollup-android-arm64": "4.34.8",
"@rollup/rollup-darwin-arm64": "4.34.7", "@rollup/rollup-darwin-arm64": "4.34.8",
"@rollup/rollup-darwin-x64": "4.34.7", "@rollup/rollup-darwin-x64": "4.34.8",
"@rollup/rollup-freebsd-arm64": "4.34.7", "@rollup/rollup-freebsd-arm64": "4.34.8",
"@rollup/rollup-freebsd-x64": "4.34.7", "@rollup/rollup-freebsd-x64": "4.34.8",
"@rollup/rollup-linux-arm-gnueabihf": "4.34.7", "@rollup/rollup-linux-arm-gnueabihf": "4.34.8",
"@rollup/rollup-linux-arm-musleabihf": "4.34.7", "@rollup/rollup-linux-arm-musleabihf": "4.34.8",
"@rollup/rollup-linux-arm64-gnu": "4.34.7", "@rollup/rollup-linux-arm64-gnu": "4.34.8",
"@rollup/rollup-linux-arm64-musl": "4.34.7", "@rollup/rollup-linux-arm64-musl": "4.34.8",
"@rollup/rollup-linux-loongarch64-gnu": "4.34.7", "@rollup/rollup-linux-loongarch64-gnu": "4.34.8",
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.7", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8",
"@rollup/rollup-linux-riscv64-gnu": "4.34.7", "@rollup/rollup-linux-riscv64-gnu": "4.34.8",
"@rollup/rollup-linux-s390x-gnu": "4.34.7", "@rollup/rollup-linux-s390x-gnu": "4.34.8",
"@rollup/rollup-linux-x64-gnu": "4.34.7", "@rollup/rollup-linux-x64-gnu": "4.34.8",
"@rollup/rollup-linux-x64-musl": "4.34.7", "@rollup/rollup-linux-x64-musl": "4.34.8",
"@rollup/rollup-win32-arm64-msvc": "4.34.7", "@rollup/rollup-win32-arm64-msvc": "4.34.8",
"@rollup/rollup-win32-ia32-msvc": "4.34.7", "@rollup/rollup-win32-ia32-msvc": "4.34.8",
"@rollup/rollup-win32-x64-msvc": "4.34.7", "@rollup/rollup-win32-x64-msvc": "4.34.8",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
@ -10647,15 +10634,15 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.24.0", "version": "8.24.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.0.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.1.tgz",
"integrity": "sha512-/lmv4366en/qbB32Vz5+kCNZEMf6xYHwh1z48suBwZvAtnXKbP+YhGe8OLE2BqC67LMqKkCNLtjejdwsdW6uOQ==", "integrity": "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.24.0", "@typescript-eslint/eslint-plugin": "8.24.1",
"@typescript-eslint/parser": "8.24.0", "@typescript-eslint/parser": "8.24.1",
"@typescript-eslint/utils": "8.24.0" "@typescript-eslint/utils": "8.24.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"

View File

@ -16,8 +16,8 @@
"@dagrejs/dagre": "^1.1.4", "@dagrejs/dagre": "^1.1.4",
"@hookform/resolvers": "^4.1.0", "@hookform/resolvers": "^4.1.0",
"@lezer/lr": "^1.4.2", "@lezer/lr": "^1.4.2",
"@tanstack/react-query": "^5.66.0", "@tanstack/react-query": "^5.66.7",
"@tanstack/react-query-devtools": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.7",
"@tanstack/react-table": "^8.21.2", "@tanstack/react-table": "^8.21.2",
"@uiw/codemirror-themes": "^4.23.8", "@uiw/codemirror-themes": "^4.23.8",
"@uiw/react-codemirror": "^4.23.8", "@uiw/react-codemirror": "^4.23.8",
@ -32,7 +32,7 @@
"react-hook-form": "^7.54.2", "react-hook-form": "^7.54.2",
"react-icons": "^5.4.0", "react-icons": "^5.4.0",
"react-intl": "^7.1.6", "react-intl": "^7.1.6",
"react-router": "^7.1.5", "react-router": "^7.2.0",
"react-select": "^5.10.0", "react-select": "^5.10.0",
"react-tabs": "^6.1.0", "react-tabs": "^6.1.0",
"react-toastify": "^11.0.3", "react-toastify": "^11.0.3",
@ -48,8 +48,8 @@
"@playwright/test": "^1.50.1", "@playwright/test": "^1.50.1",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^22.13.4", "@types/node": "^22.13.4",
"@types/react": "^19.0.8", "@types/react": "^19.0.10",
"@types/react-dom": "^19.0.3", "@types/react-dom": "^19.0.4",
"@typescript-eslint/eslint-plugin": "^8.0.1", "@typescript-eslint/eslint-plugin": "^8.0.1",
"@typescript-eslint/parser": "^8.0.1", "@typescript-eslint/parser": "^8.0.1",
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
@ -67,7 +67,7 @@
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"ts-jest": "^29.2.5", "ts-jest": "^29.2.5",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"typescript-eslint": "^8.24.0", "typescript-eslint": "^8.24.1",
"vite": "^6.1.0" "vite": "^6.1.0"
}, },
"overrides": { "overrides": {

View File

@ -11,6 +11,7 @@ import { GlobalDialogs } from './GlobalDialogs';
import { GlobalLoader } from './GlobalLoader'; import { GlobalLoader } from './GlobalLoader';
import { ToasterThemed } from './GlobalToaster'; import { ToasterThemed } from './GlobalToaster';
import { GlobalTooltips } from './GlobalTooltips'; import { GlobalTooltips } from './GlobalTooltips';
import { MutationErrors } from './MutationErrors';
import { Navigation } from './Navigation'; import { Navigation } from './Navigation';
function ApplicationLayout() { function ApplicationLayout() {
@ -48,6 +49,7 @@ function ApplicationLayout() {
> >
<main className='cc-scroll-y' style={{ overflowY: showScroll ? 'scroll' : 'auto', minHeight: mainHeight }}> <main className='cc-scroll-y' style={{ overflowY: showScroll ? 'scroll' : 'auto', minHeight: mainHeight }}>
<GlobalLoader /> <GlobalLoader />
<MutationErrors />
<Outlet /> <Outlet />
</main> </main>
{!noNavigation && !noFooter ? <Footer /> : null} {!noNavigation && !noFooter ? <Footer /> : null}

View File

@ -0,0 +1,40 @@
import clsx from 'clsx';
import { useMutationErrors } from '@/backend/useMutationErrors';
import { Button } from '@/components/Control';
import { DescribeError } from '@/components/InfoError';
import useEscapeKey from '@/hooks/useEscapeKey';
import { useDialogsStore } from '@/stores/dialogs';
export function MutationErrors() {
const { mutationErrors, resetErrors } = useMutationErrors();
const hideDialog = useDialogsStore(state => state.hideDialog);
useEscapeKey(resetErrors, mutationErrors.length > 0);
if (mutationErrors.length === 0) {
return null;
}
hideDialog();
return (
<div className='fixed top-0 left-0 w-full h-full z-modal cursor-default'>
<div className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'backdrop-blur-[3px] opacity-50')} />
<div className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'bg-prim-0 opacity-25')} />
<div
className={clsx(
'px-10 mb-10 py-3 flex flex-col items-center',
'z-modal absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-1/2',
'border rounded-xl bg-prim-100'
)}
>
<h1 className='py-2 select-none'>Ошибка при обработке</h1>
<div className={clsx('px-3 flex flex-col', 'text-warn-600 text-sm font-semibold', 'select-text')}>
<DescribeError error={mutationErrors[0]} />
</div>
<Button onClick={resetErrors} className='w-fit' text='Закрыть' />
</div>
</div>
);
}

View File

@ -54,7 +54,7 @@ export const NavigationState = ({ children }: React.PropsWithChildren) => {
} }
if (validate()) { if (validate()) {
scrollTop(); scrollTop();
Promise.resolve(router(path)).catch(console.log); Promise.resolve(router(path, { viewTransition: true })).catch(console.log);
setIsBlocked(false); setIsBlocked(false);
} }
}, },
@ -65,7 +65,7 @@ export const NavigationState = ({ children }: React.PropsWithChildren) => {
(path: string) => { (path: string) => {
if (validate()) { if (validate()) {
scrollTop(); scrollTop();
Promise.resolve(router(path, { replace: true })).catch(console.log); Promise.resolve(router(path, { replace: true, viewTransition: true })).catch(console.log);
setIsBlocked(false); setIsBlocked(false);
} }
}, },

View File

@ -100,7 +100,6 @@ export function axiosPost<RequestData, ResponseData = void>({
} else { } else {
toast.error(extractErrorMessage(error)); toast.error(extractErrorMessage(error));
} }
console.error(error);
throw error; throw error;
}); });
} }
@ -130,7 +129,6 @@ export function axiosDelete<RequestData, ResponseData = void>({
} else { } else {
toast.error(extractErrorMessage(error)); toast.error(extractErrorMessage(error));
} }
console.error(error);
throw error; throw error;
}); });
} }
@ -160,7 +158,6 @@ export function axiosPatch<RequestData, ResponseData = void>({
} else { } else {
toast.error(extractErrorMessage(error)); toast.error(extractErrorMessage(error));
} }
console.error(error);
throw error; throw error;
}); });
} }

View File

@ -11,10 +11,12 @@ export const DELAYS = {
/** API keys for local cache. */ /** API keys for local cache. */
export const KEYS = { export const KEYS = {
oss: 'oss', oss: 'oss',
auth: 'auth',
rsform: 'rsform', rsform: 'rsform',
library: 'library', library: 'library',
users: 'users', users: 'users',
cctext: 'cctext', cctext: 'cctext',
global_mutation: 'global_mutation',
composite: { composite: {
libraryList: ['library', 'list'], libraryList: ['library', 'list'],

View File

@ -1,11 +1,12 @@
import { QueryClient } from '@tanstack/react-query'; import { QueryClient } from '@tanstack/react-query';
import { ZodError } from 'zod';
import { AxiosError } from './apiTransport'; import { AxiosError } from './apiTransport';
import { DELAYS } from './configuration'; import { DELAYS } from './configuration';
declare module '@tanstack/react-query' { declare module '@tanstack/react-query' {
interface Register { interface Register {
defaultError: AxiosError; defaultError: AxiosError | ZodError;
} }
} }

View File

@ -0,0 +1,21 @@
import { useState } from 'react';
import { useMutationState, useQueryClient } from '@tanstack/react-query';
import { KEYS } from './configuration';
export const useMutationErrors = () => {
const queryClient = useQueryClient();
const [ignored, setIgnored] = useState<(Error | null)[]>([]);
const mutationErrors = useMutationState({
filters: { mutationKey: [KEYS.global_mutation], status: 'error' },
select: mutation => mutation.state.error
});
console.log(queryClient.getMutationCache().getAll());
function resetErrors() {
setIgnored(mutationErrors);
}
return { mutationErrors: mutationErrors.filter(error => !ignored.includes(error)), resetErrors };
};

View File

@ -12,21 +12,21 @@ interface InfoErrorProps {
error: ErrorData; error: ErrorData;
} }
function DescribeError({ error }: { error: ErrorData }) { export function DescribeError({ error }: { error: ErrorData }) {
if (!error) { if (!error) {
return <p>Ошибки отсутствуют</p>; return <p>Ошибки отсутствуют</p>;
} else if (typeof error === 'string') { } else if (typeof error === 'string') {
return <p>{error}</p>; return <p>{error}</p>;
} else if (error instanceof ZodError) { } else if (error instanceof ZodError) {
return ( return (
<div className='mt-6'> <div>
<p>Ошибка валидации данных</p> <p>Ошибка валидации данных</p>
<PrettyJson data={JSON.parse(error.toString()) as unknown} />; <PrettyJson data={JSON.parse(error.toString()) as unknown} />;
</div> </div>
); );
} else if (!isAxiosError(error)) { } else if (!isAxiosError(error)) {
return ( return (
<div className='mt-6'> <div>
<p> <p>
<b>Error:</b> {error.name} <b>Error:</b> {error.name}
</p> </p>
@ -96,7 +96,7 @@ export function InfoError({ error }: InfoErrorProps) {
'select-text' 'select-text'
)} )}
> >
<div className='font-normal clr-text-default'> <div className='font-normal clr-text-default mb-6'>
<p>Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту portal@acconcept.ru</p> <p>Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту portal@acconcept.ru</p>
<br /> <br />
<p>Для продолжения работы перезагрузите страницу</p> <p>Для продолжения работы перезагрузите страницу</p>

View File

@ -1,7 +1,7 @@
import { queryOptions } from '@tanstack/react-query'; import { queryOptions } from '@tanstack/react-query';
import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
import { DELAYS } from '@/backend/configuration'; import { DELAYS, KEYS } from '@/backend/configuration';
import { infoMsg } from '@/utils/labels'; import { infoMsg } from '@/utils/labels';
import { import {
@ -17,7 +17,7 @@ import {
* Authentication API. * Authentication API.
*/ */
export const authApi = { export const authApi = {
baseKey: 'auth', baseKey: KEYS.auth,
getAuthQueryOptions: () => { getAuthQueryOptions: () => {
return queryOptions({ return queryOptions({

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
import { IChangePasswordDTO } from './types'; import { IChangePasswordDTO } from './types';
export const useChangePassword = () => { export const useChangePassword = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['change-password'], mutationKey: [KEYS.auth, 'change-password'],
mutationFn: authApi.changePassword, mutationFn: authApi.changePassword,
onSettled: () => client.invalidateQueries({ queryKey: [authApi.baseKey] }) onSettled: () => client.invalidateQueries({ queryKey: [authApi.baseKey] })
}); });

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
import { IUserLoginDTO } from './types'; import { IUserLoginDTO } from './types';
export const useLogin = () => { export const useLogin = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['login'], mutationKey: [KEYS.auth, 'login'],
mutationFn: authApi.login, mutationFn: authApi.login,
onSettled: () => client.invalidateQueries({ queryKey: [authApi.baseKey] }), onSettled: () => client.invalidateQueries({ queryKey: [authApi.baseKey] }),
onSuccess: () => client.resetQueries() onSuccess: () => client.resetQueries()

View File

@ -1,11 +1,13 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
export const useLogout = () => { export const useLogout = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['logout'], mutationKey: [KEYS.auth, 'logout'],
mutationFn: authApi.logout, mutationFn: authApi.logout,
onSuccess: () => client.resetQueries() onSuccess: () => client.resetQueries()
}); });

View File

@ -1,11 +1,13 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
import { IRequestPasswordDTO } from './types'; import { IRequestPasswordDTO } from './types';
export const useRequestPasswordReset = () => { export const useRequestPasswordReset = () => {
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['request-password-reset'], mutationKey: [KEYS.auth, 'request-password-reset'],
mutationFn: authApi.requestPasswordReset mutationFn: authApi.requestPasswordReset
}); });
return { return {

View File

@ -1,15 +1,17 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { authApi } from './api'; import { authApi } from './api';
import { IPasswordTokenDTO, IResetPasswordDTO } from './types'; import { IPasswordTokenDTO, IResetPasswordDTO } from './types';
export const useResetPassword = () => { export const useResetPassword = () => {
const validateMutation = useMutation({ const validateMutation = useMutation({
mutationKey: ['validate-token'], mutationKey: [KEYS.auth, 'validate-token'],
mutationFn: authApi.validatePasswordToken mutationFn: authApi.validatePasswordToken
}); });
const resetMutation = useMutation({ const resetMutation = useMutation({
mutationKey: ['reset-password'], mutationKey: [KEYS.auth, 'reset-password'],
mutationFn: authApi.resetPassword mutationFn: authApi.resetPassword
}); });
return { return {

View File

@ -1,14 +1,17 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { libraryApi } from './api'; import { libraryApi } from './api';
import { ICloneLibraryItemDTO } from './types'; import { ICloneLibraryItemDTO } from './types';
export const useCloneItem = () => { export const useCloneItem = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'clone-item'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'clone-item'],
mutationFn: libraryApi.cloneItem, mutationFn: libraryApi.cloneItem,
onSuccess: () => client.invalidateQueries({ queryKey: [libraryApi.baseKey] }) onSuccess: () => client.invalidateQueries({ queryKey: [libraryApi.baseKey] }),
onError: () => client.invalidateQueries()
}); });
return { return {
cloneItem: (data: ICloneLibraryItemDTO) => mutation.mutateAsync(data) cloneItem: (data: ICloneLibraryItemDTO) => mutation.mutateAsync(data)

View File

@ -1,14 +1,17 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { libraryApi } from './api'; import { libraryApi } from './api';
import { ICreateLibraryItemDTO } from './types'; import { ICreateLibraryItemDTO } from './types';
export const useCreateItem = () => { export const useCreateItem = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'create-item'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'create-item'],
mutationFn: libraryApi.createItem, mutationFn: libraryApi.createItem,
onSuccess: () => client.invalidateQueries({ queryKey: [libraryApi.baseKey] }) onSuccess: () => client.invalidateQueries({ queryKey: [libraryApi.baseKey] }),
onError: () => client.invalidateQueries()
}); });
return { return {
createItem: (data: ICreateLibraryItemDTO) => mutation.mutateAsync(data), createItem: (data: ICreateLibraryItemDTO) => mutation.mutateAsync(data),

View File

@ -8,7 +8,7 @@ import { libraryApi } from './api';
export const useDeleteItem = () => { export const useDeleteItem = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'delete-item'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'delete-item'],
mutationFn: libraryApi.deleteItem, mutationFn: libraryApi.deleteItem,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
client.invalidateQueries({ queryKey: libraryApi.libraryListKey }).catch(console.error); client.invalidateQueries({ queryKey: libraryApi.libraryListKey }).catch(console.error);
@ -21,7 +21,8 @@ export const useDeleteItem = () => {
]).catch(console.error), ]).catch(console.error),
PARAMETER.navigationDuration PARAMETER.navigationDuration
); );
} },
onError: () => client.invalidateQueries()
}); });
return { return {
deleteItem: (target: number) => mutation.mutateAsync(target), deleteItem: (target: number) => mutation.mutateAsync(target),

View File

@ -3,8 +3,8 @@ import { useIsMutating } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
export const useMutatingLibrary = () => { export const useMutatingLibrary = () => {
const countMutations = useIsMutating({ mutationKey: [KEYS.library] }); const countMutations = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.library] });
const countOss = useIsMutating({ mutationKey: [KEYS.oss] }); const countOss = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.oss] });
const countRSForm = useIsMutating({ mutationKey: [KEYS.rsform] }); const countRSForm = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.rsform] });
return countMutations + countOss + countRSForm !== 0; return countMutations + countOss + countRSForm !== 0;
}; };

View File

@ -15,7 +15,8 @@ export const useRenameLocation = () => {
client.invalidateQueries({ queryKey: [KEYS.library] }), client.invalidateQueries({ queryKey: [KEYS.library] }),
client.invalidateQueries({ queryKey: [KEYS.rsform] }), client.invalidateQueries({ queryKey: [KEYS.rsform] }),
client.invalidateQueries({ queryKey: [KEYS.oss] }) client.invalidateQueries({ queryKey: [KEYS.oss] })
]) ]),
onError: () => client.invalidateQueries()
}); });
return { return {
renameLocation: (data: IRenameLocationDTO) => mutation.mutateAsync(data) renameLocation: (data: IRenameLocationDTO) => mutation.mutateAsync(data)

View File

@ -11,7 +11,7 @@ import { AccessPolicy, ILibraryItem } from './types';
export const useSetAccessPolicy = () => { export const useSetAccessPolicy = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'set-location'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'set-location'],
mutationFn: libraryApi.setAccessPolicy, mutationFn: libraryApi.setAccessPolicy,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID });
@ -39,7 +39,8 @@ export const useSetAccessPolicy = () => {
client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) =>
prev?.map(item => (item.id === variables.itemID ? { ...item, access_policy: variables.policy } : item)) prev?.map(item => (item.id === variables.itemID ? { ...item, access_policy: variables.policy } : item))
); );
} },
onError: () => client.invalidateQueries()
}); });
return { return {

View File

@ -10,7 +10,7 @@ import { libraryApi } from './api';
export const useSetEditors = () => { export const useSetEditors = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'set-location'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'set-location'],
mutationFn: libraryApi.setEditors, mutationFn: libraryApi.setEditors,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID });
@ -34,7 +34,8 @@ export const useSetEditors = () => {
client.setQueryData(rsKey, (prev: IRSFormDTO | undefined) => client.setQueryData(rsKey, (prev: IRSFormDTO | undefined) =>
!prev ? undefined : { ...prev, editors: variables.editors } !prev ? undefined : { ...prev, editors: variables.editors }
); );
} },
onError: () => client.invalidateQueries()
}); });
return { return {

View File

@ -11,7 +11,7 @@ import { ILibraryItem } from './types';
export const useSetLocation = () => { export const useSetLocation = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'set-location'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'set-location'],
mutationFn: libraryApi.setLocation, mutationFn: libraryApi.setLocation,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID });
@ -39,7 +39,8 @@ export const useSetLocation = () => {
client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) =>
prev?.map(item => (item.id === variables.itemID ? { ...item, location: variables.location } : item)) prev?.map(item => (item.id === variables.itemID ? { ...item, location: variables.location } : item))
); );
} },
onError: () => client.invalidateQueries()
}); });
return { return {

View File

@ -11,7 +11,7 @@ import { ILibraryItem } from './types';
export const useSetOwner = () => { export const useSetOwner = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'set-owner'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'set-owner'],
mutationFn: libraryApi.setOwner, mutationFn: libraryApi.setOwner,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID });
@ -39,7 +39,8 @@ export const useSetOwner = () => {
client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) =>
prev?.map(item => (item.id === variables.itemID ? { ...item, owner: variables.owner } : item)) prev?.map(item => (item.id === variables.itemID ? { ...item, owner: variables.owner } : item))
); );
} },
onError: () => client.invalidateQueries()
}); });
return { return {

View File

@ -11,7 +11,7 @@ import { ILibraryItem, IUpdateLibraryItemDTO, LibraryItemType } from './types';
export const useUpdateItem = () => { export const useUpdateItem = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'update-item'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'update-item'],
mutationFn: libraryApi.updateItem, mutationFn: libraryApi.updateItem,
onSuccess: (data: ILibraryItem) => { onSuccess: (data: ILibraryItem) => {
const itemKey = const itemKey =
@ -32,7 +32,8 @@ export const useUpdateItem = () => {
); );
} }
} }
} },
onError: () => client.invalidateQueries()
}); });
return { return {
updateItem: (data: IUpdateLibraryItemDTO) => mutation.mutateAsync(data) updateItem: (data: IUpdateLibraryItemDTO) => mutation.mutateAsync(data)

View File

@ -10,12 +10,13 @@ export const useVersionCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'create-version'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'create-version'],
mutationFn: libraryApi.versionCreate, mutationFn: libraryApi.versionCreate,
onSuccess: data => { onSuccess: data => {
client.setQueryData(KEYS.composite.rsItem({ itemID: data.schema.id }), data.schema); client.setQueryData(KEYS.composite.rsItem({ itemID: data.schema.id }), data.schema);
updateTimestamp(data.schema.id); updateTimestamp(data.schema.id);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
versionCreate: (data: { itemID: number; data: IVersionCreateDTO }) => versionCreate: (data: { itemID: number; data: IVersionCreateDTO }) =>

View File

@ -9,7 +9,7 @@ import { libraryApi } from './api';
export const useVersionDelete = () => { export const useVersionDelete = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'delete-version'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'delete-version'],
mutationFn: libraryApi.versionDelete, mutationFn: libraryApi.versionDelete,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) => client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) =>
@ -20,7 +20,8 @@ export const useVersionDelete = () => {
versions: prev.versions.filter(version => version.id !== variables.versionID) versions: prev.versions.filter(version => version.id !== variables.versionID)
} }
); );
} },
onError: () => client.invalidateQueries()
}); });
return { return {
versionDelete: (data: { itemID: number; versionID: number }) => mutation.mutateAsync(data) versionDelete: (data: { itemID: number; versionID: number }) => mutation.mutateAsync(data)

View File

@ -7,12 +7,13 @@ import { libraryApi } from './api';
export const useVersionRestore = () => { export const useVersionRestore = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'restore-version'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'restore-version'],
mutationFn: libraryApi.versionRestore, mutationFn: libraryApi.versionRestore,
onSuccess: data => { onSuccess: data => {
client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data); client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data);
return client.invalidateQueries({ queryKey: [libraryApi.baseKey] }); return client.invalidateQueries({ queryKey: [libraryApi.baseKey] });
} },
onError: () => client.invalidateQueries()
}); });
return { return {
versionRestore: (data: { versionID: number }) => mutation.mutateAsync(data) versionRestore: (data: { versionID: number }) => mutation.mutateAsync(data)

View File

@ -10,7 +10,7 @@ import { IVersionUpdateDTO } from './types';
export const useVersionUpdate = () => { export const useVersionUpdate = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'update-version'], mutationKey: [KEYS.global_mutation, libraryApi.baseKey, 'update-version'],
mutationFn: libraryApi.versionUpdate, mutationFn: libraryApi.versionUpdate,
onSuccess: (data, variables) => { onSuccess: (data, variables) => {
client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) => client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) =>
@ -23,7 +23,8 @@ export const useVersionUpdate = () => {
) )
} }
); );
} },
onError: () => client.invalidateQueries()
}); });
return { return {
versionUpdate: (data: { itemID: number; version: IVersionUpdateDTO }) => mutation.mutateAsync(data) versionUpdate: (data: { itemID: number; version: IVersionUpdateDTO }) => mutation.mutateAsync(data)

View File

@ -1,11 +1,13 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { ossApi } from './api'; import { ossApi } from './api';
export const useFindPredecessor = () => { export const useFindPredecessor = () => {
const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'find-predecessor'], mutationKey: [ossApi.baseKey, 'find-predecessor'],
mutationFn: ossApi.getPredecessor mutationFn: ossApi.getPredecessor,
onError: () => client.invalidateQueries()
}); });
return { return {
findPredecessor: (target: number) => mutation.mutateAsync({ target: target }) findPredecessor: (target: number) => mutation.mutateAsync({ target: target })

View File

@ -8,7 +8,7 @@ import { ITargetOperation } from './types';
export const useInputCreate = () => { export const useInputCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'input-create'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'input-create'],
mutationFn: ossApi.inputCreate, mutationFn: ossApi.inputCreate,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss);
@ -16,7 +16,8 @@ export const useInputCreate = () => {
client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), client.invalidateQueries({ queryKey: KEYS.composite.libraryList }),
client.invalidateQueries({ queryKey: [KEYS.rsform] }) client.invalidateQueries({ queryKey: [KEYS.rsform] })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
inputCreate: (data: { itemID: number; data: ITargetOperation }) => inputCreate: (data: { itemID: number; data: ITargetOperation }) =>

View File

@ -8,7 +8,7 @@ import { IInputUpdateDTO } from './types';
export const useInputUpdate = () => { export const useInputUpdate = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'input-update'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'input-update'],
mutationFn: ossApi.inputUpdate, mutationFn: ossApi.inputUpdate,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);
@ -16,7 +16,8 @@ export const useInputUpdate = () => {
client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), client.invalidateQueries({ queryKey: KEYS.composite.libraryList }),
client.invalidateQueries({ queryKey: [KEYS.rsform] }) client.invalidateQueries({ queryKey: [KEYS.rsform] })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
inputUpdate: (data: { itemID: number; data: IInputUpdateDTO }) => mutation.mutateAsync(data) inputUpdate: (data: { itemID: number; data: IInputUpdateDTO }) => mutation.mutateAsync(data)

View File

@ -3,7 +3,7 @@ import { useIsMutating } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
export const useMutatingOss = () => { export const useMutatingOss = () => {
const countLibrary = useIsMutating({ mutationKey: [KEYS.library] }); const countLibrary = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.library] });
const countOss = useIsMutating({ mutationKey: [KEYS.oss] }); const countOss = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.oss] });
return countLibrary + countOss !== 0; return countLibrary + countOss !== 0;
}; };

View File

@ -2,6 +2,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useUpdateTimestamp } from '@/features/library'; import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration';
import { ossApi } from './api'; import { ossApi } from './api';
import { IOperationCreateDTO } from './types'; import { IOperationCreateDTO } from './types';
@ -9,12 +11,13 @@ export const useOperationCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-create'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'operation-create'],
mutationFn: ossApi.operationCreate, mutationFn: ossApi.operationCreate,
onSuccess: response => { onSuccess: response => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: response.oss.id }).queryKey, response.oss); client.setQueryData(ossApi.getOssQueryOptions({ itemID: response.oss.id }).queryKey, response.oss);
updateTimestamp(response.oss.id); updateTimestamp(response.oss.id);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
operationCreate: (data: { itemID: number; data: IOperationCreateDTO }) => mutation.mutateAsync(data) operationCreate: (data: { itemID: number; data: IOperationCreateDTO }) => mutation.mutateAsync(data)

View File

@ -8,7 +8,7 @@ import { IOperationDeleteDTO } from './types';
export const useOperationDelete = () => { export const useOperationDelete = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-delete'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'operation-delete'],
mutationFn: ossApi.operationDelete, mutationFn: ossApi.operationDelete,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);
@ -16,7 +16,8 @@ export const useOperationDelete = () => {
client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), client.invalidateQueries({ queryKey: KEYS.composite.libraryList }),
client.invalidateQueries({ queryKey: [KEYS.rsform] }) client.invalidateQueries({ queryKey: [KEYS.rsform] })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
operationDelete: (data: { itemID: number; data: IOperationDeleteDTO }) => mutation.mutateAsync(data) operationDelete: (data: { itemID: number; data: IOperationDeleteDTO }) => mutation.mutateAsync(data)

View File

@ -8,7 +8,7 @@ import { ITargetOperation } from './types';
export const useOperationExecute = () => { export const useOperationExecute = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-execute'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'operation-execute'],
mutationFn: ossApi.operationExecute, mutationFn: ossApi.operationExecute,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);
@ -16,7 +16,8 @@ export const useOperationExecute = () => {
client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), client.invalidateQueries({ queryKey: KEYS.composite.libraryList }),
client.invalidateQueries({ queryKey: [KEYS.rsform] }) client.invalidateQueries({ queryKey: [KEYS.rsform] })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
operationExecute: (data: { itemID: number; data: ITargetOperation }) => mutation.mutateAsync(data) operationExecute: (data: { itemID: number; data: ITargetOperation }) => mutation.mutateAsync(data)

View File

@ -10,7 +10,7 @@ import { IOperationUpdateDTO } from './types';
export const useOperationUpdate = () => { export const useOperationUpdate = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-update'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'operation-update'],
mutationFn: ossApi.operationUpdate, mutationFn: ossApi.operationUpdate,
onSuccess: (data, variables) => { onSuccess: (data, variables) => {
client.setQueryData(KEYS.composite.ossItem({ itemID: data.id }), data); client.setQueryData(KEYS.composite.ossItem({ itemID: data.id }), data);
@ -28,7 +28,8 @@ export const useOperationUpdate = () => {
return client.invalidateQueries({ return client.invalidateQueries({
queryKey: KEYS.composite.rsItem({ itemID: schemaID }) queryKey: KEYS.composite.rsItem({ itemID: schemaID })
}); });
} },
onError: () => client.invalidateQueries()
}); });
return { return {
operationUpdate: (data: { itemID: number; data: IOperationUpdateDTO }) => mutation.mutateAsync(data) operationUpdate: (data: { itemID: number; data: IOperationUpdateDTO }) => mutation.mutateAsync(data)

View File

@ -8,7 +8,7 @@ import { ICstRelocateDTO } from './types';
export const useRelocateConstituents = () => { export const useRelocateConstituents = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'relocate-constituents'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'relocate-constituents'],
mutationFn: ossApi.relocateConstituents, mutationFn: ossApi.relocateConstituents,
onSuccess: data => { onSuccess: data => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);
@ -16,7 +16,8 @@ export const useRelocateConstituents = () => {
client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), client.invalidateQueries({ queryKey: KEYS.composite.libraryList }),
client.invalidateQueries({ queryKey: [KEYS.rsform] }) client.invalidateQueries({ queryKey: [KEYS.rsform] })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
relocateConstituents: (data: ICstRelocateDTO) => mutation.mutateAsync(data) relocateConstituents: (data: ICstRelocateDTO) => mutation.mutateAsync(data)

View File

@ -1,16 +1,20 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useUpdateTimestamp } from '@/features/library'; import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration';
import { ossApi } from './api'; import { ossApi } from './api';
import { IOperationPosition } from './types'; import { IOperationPosition } from './types';
export const useUpdatePositions = () => { export const useUpdatePositions = () => {
const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'update-positions'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'update-positions'],
mutationFn: ossApi.updatePositions, mutationFn: ossApi.updatePositions,
onSuccess: (_, variables) => updateTimestamp(variables.itemID) onSuccess: (_, variables) => updateTimestamp(variables.itemID),
onError: () => client.invalidateQueries()
}); });
return { return {
updatePositions: (data: { updatePositions: (data: {

View File

@ -1,7 +1,7 @@
'use client'; 'use client';
import { Suspense, useState } from 'react'; import { Suspense, useState } from 'react';
import { FormProvider, useForm, useWatch } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import clsx from 'clsx'; import clsx from 'clsx';
@ -51,11 +51,9 @@ function DlgEditOperation() {
substitution: sub.substitution substitution: sub.substitution
})), })),
positions: positions positions: positions
} },
mode: 'onChange'
}); });
const alias = useWatch({ control: methods.control, name: 'item_data.alias' });
const isValid = alias !== '';
const [activeTab, setActiveTab] = useState(TabID.CARD); const [activeTab, setActiveTab] = useState(TabID.CARD);
function onSubmit(data: IOperationUpdateDTO) { function onSubmit(data: IOperationUpdateDTO) {
@ -66,7 +64,7 @@ function DlgEditOperation() {
<ModalForm <ModalForm
header='Редактирование операции' header='Редактирование операции'
submitText='Сохранить' submitText='Сохранить'
canSubmit={isValid} canSubmit={methods.formState.isValid}
onSubmit={event => void methods.handleSubmit(onSubmit)(event)} onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
className='w-[40rem] px-6 h-[32rem]' className='w-[40rem] px-6 h-[32rem]'
helpTopic={HelpTopic.UI_SUBSTITUTIONS} helpTopic={HelpTopic.UI_SUBSTITUTIONS}

View File

@ -1,11 +1,13 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
import { ICheckConstituentaDTO } from './types'; import { ICheckConstituentaDTO } from './types';
export const useCheckConstituenta = () => { export const useCheckConstituenta = () => {
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['actions', 'check-constituenta'], mutationKey: [KEYS.global_mutation, 'actions', 'check-constituenta'],
mutationFn: rsformsApi.checkConstituenta mutationFn: rsformsApi.checkConstituenta
}); });
return { return {

View File

@ -11,7 +11,7 @@ export const useCstCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'create-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'create-cst'],
mutationFn: rsformsApi.cstCreate, mutationFn: rsformsApi.cstCreate,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema);
@ -24,7 +24,8 @@ export const useCstCreate = () => {
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id
}) })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
cstCreate: (data: { itemID: number; data: ICstCreateDTO }) => cstCreate: (data: { itemID: number; data: ICstCreateDTO }) =>

View File

@ -11,7 +11,7 @@ export const useCstDelete = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'delete-multiple-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'delete-multiple-cst'],
mutationFn: rsformsApi.cstDelete, mutationFn: rsformsApi.cstDelete,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);
@ -24,7 +24,8 @@ export const useCstDelete = () => {
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id
}) })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
cstDelete: (data: { itemID: number; data: IConstituentaList }) => mutation.mutateAsync(data) cstDelete: (data: { itemID: number; data: IConstituentaList }) => mutation.mutateAsync(data)

View File

@ -2,6 +2,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useUpdateTimestamp } from '@/features/library'; import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
import { ICstMoveDTO } from './types'; import { ICstMoveDTO } from './types';
@ -9,12 +11,13 @@ export const useCstMove = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'move-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'move-cst'],
mutationFn: rsformsApi.cstMove, mutationFn: rsformsApi.cstMove,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);
updateTimestamp(data.id); updateTimestamp(data.id);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
cstMove: (data: { itemID: number; data: ICstMoveDTO }) => mutation.mutateAsync(data) cstMove: (data: { itemID: number; data: ICstMoveDTO }) => mutation.mutateAsync(data)

View File

@ -11,7 +11,7 @@ export const useCstRename = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'rename-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'rename-cst'],
mutationFn: rsformsApi.cstRename, mutationFn: rsformsApi.cstRename,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema);
@ -24,7 +24,8 @@ export const useCstRename = () => {
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id
}) })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
cstRename: (data: { itemID: number; data: ICstRenameDTO }) => mutation.mutateAsync(data) cstRename: (data: { itemID: number; data: ICstRenameDTO }) => mutation.mutateAsync(data)

View File

@ -11,7 +11,7 @@ export const useCstSubstitute = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'substitute-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'substitute-cst'],
mutationFn: rsformsApi.cstSubstitute, mutationFn: rsformsApi.cstSubstitute,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);
@ -24,7 +24,8 @@ export const useCstSubstitute = () => {
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id
}) })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
cstSubstitute: (data: { itemID: number; data: ICstSubstitutionsDTO }) => mutation.mutateAsync(data) cstSubstitute: (data: { itemID: number; data: ICstSubstitutionsDTO }) => mutation.mutateAsync(data)

View File

@ -11,7 +11,7 @@ export const useCstUpdate = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'update-cst'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'update-cst'],
mutationFn: rsformsApi.cstUpdate, mutationFn: rsformsApi.cstUpdate,
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
updateTimestamp(variables.itemID); updateTimestamp(variables.itemID);
@ -20,7 +20,8 @@ export const useCstUpdate = () => {
client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [KEYS.oss] }),
client.invalidateQueries({ queryKey: [rsformsApi.baseKey] }) client.invalidateQueries({ queryKey: [rsformsApi.baseKey] })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
cstUpdate: (data: { itemID: number; data: ICstUpdateDTO }) => mutation.mutateAsync(data) cstUpdate: (data: { itemID: number; data: ICstUpdateDTO }) => mutation.mutateAsync(data)

View File

@ -1,10 +1,12 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
export const useDownloadRSForm = () => { export const useDownloadRSForm = () => {
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'download'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'download'],
mutationFn: rsformsApi.download mutationFn: rsformsApi.download
}); });
return { return {

View File

@ -11,7 +11,7 @@ export const useInlineSynthesis = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'inline-synthesis'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'inline-synthesis'],
mutationFn: rsformsApi.inlineSynthesis, mutationFn: rsformsApi.inlineSynthesis,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);
@ -24,7 +24,8 @@ export const useInlineSynthesis = () => {
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id
}) })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
inlineSynthesis: (data: IInlineSynthesisDTO) => mutation.mutateAsync(data) inlineSynthesis: (data: IInlineSynthesisDTO) => mutation.mutateAsync(data)

View File

@ -3,7 +3,7 @@ import { useIsMutating } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
export const useMutatingRSForm = () => { export const useMutatingRSForm = () => {
const countLibrary = useIsMutating({ mutationKey: [KEYS.library] }); const countLibrary = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.library] });
const countRsform = useIsMutating({ mutationKey: [KEYS.rsform] }); const countRsform = useIsMutating({ mutationKey: [KEYS.global_mutation, KEYS.rsform] });
return countLibrary + countRsform !== 0; return countLibrary + countRsform !== 0;
}; };

View File

@ -11,7 +11,7 @@ export const useProduceStructure = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'produce-structure'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'produce-structure'],
mutationFn: rsformsApi.produceStructure, mutationFn: rsformsApi.produceStructure,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema);
@ -24,7 +24,8 @@ export const useProduceStructure = () => {
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id
}) })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
produceStructure: (data: { itemID: number; data: ITargetCst }) => produceStructure: (data: { itemID: number; data: ITargetCst }) =>

View File

@ -10,7 +10,7 @@ export const useResetAliases = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'reset-aliases'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'reset-aliases'],
mutationFn: rsformsApi.resetAliases, mutationFn: rsformsApi.resetAliases,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);
@ -23,7 +23,8 @@ export const useResetAliases = () => {
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id
}) })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
resetAliases: (data: { itemID: number }) => mutation.mutateAsync(data) resetAliases: (data: { itemID: number }) => mutation.mutateAsync(data)

View File

@ -2,18 +2,21 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useUpdateTimestamp } from '@/features/library'; import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
export const useRestoreOrder = () => { export const useRestoreOrder = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'restore-order'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'restore-order'],
mutationFn: rsformsApi.restoreOrder, mutationFn: rsformsApi.restoreOrder,
onSuccess: data => { onSuccess: data => {
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data);
updateTimestamp(data.id); updateTimestamp(data.id);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
restoreOrder: (data: { itemID: number }) => mutation.mutateAsync(data) restoreOrder: (data: { itemID: number }) => mutation.mutateAsync(data)

View File

@ -10,7 +10,7 @@ import { IRSFormUploadDTO } from './types';
export const useUploadTRS = () => { export const useUploadTRS = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [rsformsApi.baseKey, 'load-trs'], mutationKey: [KEYS.global_mutation, rsformsApi.baseKey, 'load-trs'],
mutationFn: rsformsApi.upload, mutationFn: rsformsApi.upload,
onSuccess: data => { onSuccess: data => {
client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data); client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data);
@ -25,7 +25,8 @@ export const useUploadTRS = () => {
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id
}) })
]); ]);
} },
onError: () => client.invalidateQueries()
}); });
return { return {
upload: (data: IRSFormUploadDTO) => mutation.mutateAsync(data) upload: (data: IRSFormUploadDTO) => mutation.mutateAsync(data)

View File

@ -10,6 +10,7 @@ import { IUpdateProfileDTO, IUserSignupDTO } from './types';
export const usersApi = { export const usersApi = {
baseKey: KEYS.users, baseKey: KEYS.users,
getUsersQueryOptions: () => getUsersQueryOptions: () =>
queryOptions({ queryOptions({
queryKey: [usersApi.baseKey, 'list'], queryKey: [usersApi.baseKey, 'list'],

View File

@ -1,12 +1,14 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { usersApi } from './api'; import { usersApi } from './api';
import { IUserSignupDTO } from './types'; import { IUserSignupDTO } from './types';
export const useSignup = () => { export const useSignup = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['signup'], mutationKey: [KEYS.users, 'signup'],
mutationFn: usersApi.signup, mutationFn: usersApi.signup,
onSuccess: () => client.invalidateQueries({ queryKey: usersApi.getUsersQueryOptions().queryKey }) onSuccess: () => client.invalidateQueries({ queryKey: usersApi.getUsersQueryOptions().queryKey })
}); });

View File

@ -1,17 +1,20 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { KEYS } from '@/backend/configuration';
import { usersApi } from './api'; import { usersApi } from './api';
import { IUpdateProfileDTO } from './types'; import { IUpdateProfileDTO } from './types';
export const useUpdateProfile = () => { export const useUpdateProfile = () => {
const client = useQueryClient(); const client = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: ['update-profile'], mutationKey: [KEYS.users, 'update-profile'],
mutationFn: usersApi.updateProfile, mutationFn: usersApi.updateProfile,
onSuccess: data => { onSuccess: data => {
client.setQueryData(usersApi.getProfileQueryOptions().queryKey, data); client.setQueryData(usersApi.getProfileQueryOptions().queryKey, data);
return client.invalidateQueries({ queryKey: usersApi.getUsersQueryOptions().queryKey }); return client.invalidateQueries({ queryKey: usersApi.getUsersQueryOptions().queryKey });
} },
onError: () => client.invalidateQueries()
}); });
return { return {
updateProfile: (data: IUpdateProfileDTO) => mutation.mutateAsync(data), updateProfile: (data: IUpdateProfileDTO) => mutation.mutateAsync(data),

View File

@ -2,7 +2,7 @@
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
function useEscapeKey(handleClose: () => void) { function useEscapeKey(handleClose: () => void, isEnabled: boolean = true) {
const handleEscKey = useCallback( const handleEscKey = useCallback(
(event: KeyboardEvent) => { (event: KeyboardEvent) => {
if (event.key === 'Escape') { if (event.key === 'Escape') {
@ -13,11 +13,13 @@ function useEscapeKey(handleClose: () => void) {
); );
useEffect(() => { useEffect(() => {
document.addEventListener('keyup', handleEscKey, false); if (isEnabled) {
return () => { document.addEventListener('keyup', handleEscKey, false);
document.removeEventListener('keyup', handleEscKey, false); return () => {
}; document.removeEventListener('keyup', handleEscKey, false);
}, [handleEscKey]); };
}
}, [handleEscKey, isEnabled]);
} }
export default useEscapeKey; export default useEscapeKey;