Compare commits
31 Commits
7792a82bf7
...
90be3b5aa7
Author | SHA1 | Date | |
---|---|---|---|
![]() |
90be3b5aa7 | ||
![]() |
aedaaa27bb | ||
![]() |
ea349c7ecc | ||
![]() |
acf0f4e9f6 | ||
![]() |
8346850cf6 | ||
![]() |
b6f1ff3337 | ||
![]() |
c0b22f5ca1 | ||
![]() |
28bfa502a4 | ||
![]() |
9d09560a17 | ||
![]() |
0e62a49fa7 | ||
![]() |
7214e4a581 | ||
![]() |
3c3a6c773b | ||
![]() |
3440b67c54 | ||
![]() |
8a4e3a6d15 | ||
![]() |
9f84154237 | ||
![]() |
8d611d5471 | ||
![]() |
6f03dba4e7 | ||
![]() |
ab2154f9bc | ||
![]() |
066ebfa83d | ||
![]() |
6187146e86 | ||
![]() |
0320dd68ab | ||
![]() |
d143bf4c3a | ||
![]() |
6eeb6ffd14 | ||
![]() |
4fbd30897b | ||
![]() |
9b0cc3107b | ||
![]() |
ddc5c7e767 | ||
![]() |
2183d659e7 | ||
![]() |
6fbb7fc9aa | ||
![]() |
ff239c9f73 | ||
![]() |
7ca4cf9ba2 | ||
![]() |
53a470352f |
|
@ -620,6 +620,8 @@ def inline_synthesis(request: Request) -> HttpResponse:
|
|||
|
||||
receiver = m.RSForm(serializer.validated_data['receiver'])
|
||||
items = cast(list[m.Constituenta], serializer.validated_data['items'])
|
||||
if len(items) == 0:
|
||||
items = list(m.RSForm(serializer.validated_data['source']).constituents().order_by('order'))
|
||||
|
||||
with transaction.atomic():
|
||||
new_items = receiver.insert_copy(items)
|
||||
|
|
488
rsconcept/frontend/package-lock.json
generated
488
rsconcept/frontend/package-lock.json
generated
|
@ -11,11 +11,11 @@
|
|||
"@dagrejs/dagre": "^1.1.4",
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@lezer/lr": "^1.4.2",
|
||||
"@tanstack/react-query": "^5.64.2",
|
||||
"@tanstack/react-query-devtools": "^5.64.2",
|
||||
"@tanstack/react-query": "^5.66.0",
|
||||
"@tanstack/react-query-devtools": "^5.66.0",
|
||||
"@tanstack/react-table": "^8.20.6",
|
||||
"@uiw/codemirror-themes": "^4.23.7",
|
||||
"@uiw/react-codemirror": "^4.23.7",
|
||||
"@uiw/codemirror-themes": "^4.23.8",
|
||||
"@uiw/react-codemirror": "^4.23.8",
|
||||
"axios": "^1.7.9",
|
||||
"clsx": "^2.1.1",
|
||||
"html-to-image": "^1.11.11",
|
||||
|
@ -27,12 +27,12 @@
|
|||
"react-hook-form": "^7.54.2",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-intl": "^7.1.5",
|
||||
"react-router": "^7.1.3",
|
||||
"react-router": "^7.1.5",
|
||||
"react-select": "^5.10.0",
|
||||
"react-tabs": "^6.1.0",
|
||||
"react-toastify": "^11.0.3",
|
||||
"react-tooltip": "^5.28.0",
|
||||
"react-zoom-pan-pinch": "^3.6.1",
|
||||
"react-zoom-pan-pinch": "^3.7.0",
|
||||
"reactflow": "^11.11.4",
|
||||
"use-debounce": "^10.0.4",
|
||||
"zod": "^3.24.1",
|
||||
|
@ -40,9 +40,9 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@lezer/generator": "^1.7.2",
|
||||
"@playwright/test": "^1.50.0",
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.10.10",
|
||||
"@types/node": "^22.13.1",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.1",
|
||||
|
@ -61,8 +61,8 @@
|
|||
"tailwindcss": "^3.4.17",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.21.0",
|
||||
"vite": "^6.0.11"
|
||||
"typescript-eslint": "^8.23.0",
|
||||
"vite": "^6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
|
@ -825,9 +825,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@codemirror/state": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.1.tgz",
|
||||
"integrity": "sha512-3rA9lcwciEB47ZevqvD8qgbzhM9qMb8vCcQCNmDfVRPQG4JT9mSb0Jg8H7YjKGGQcFnLN323fj9jdnG59Kx6bg==",
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
||||
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@marijn/find-cluster-break": "^1.0.0"
|
||||
|
@ -1458,13 +1458,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz",
|
||||
"integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==",
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz",
|
||||
"integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/object-schema": "^2.1.5",
|
||||
"@eslint/object-schema": "^2.1.6",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.1.2"
|
||||
},
|
||||
|
@ -1581,9 +1581,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@eslint/object-schema": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz",
|
||||
"integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==",
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
|
||||
"integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
|
@ -2430,13 +2430,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.50.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.0.tgz",
|
||||
"integrity": "sha512-ZGNXbt+d65EGjBORQHuYKj+XhCewlwpnSd/EDuLPZGSiEWmgOJB5RmMCCYGy5aMfTs9wx61RivfDKi8H/hcMvw==",
|
||||
"version": "1.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz",
|
||||
"integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.50.0"
|
||||
"playwright": "1.50.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
|
@ -2716,9 +2716,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.0.tgz",
|
||||
"integrity": "sha512-G2fUQQANtBPsNwiVFg4zKiPQyjVKZCUdQUol53R8E71J7AsheRMV/Yv/nB8giOcOVqP7//eB5xPqieBYZe9bGg==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.4.tgz",
|
||||
"integrity": "sha512-gGi5adZWvjtJU7Axs//CWaQbQd/vGy8KGcnEaCWiyCqxWYDxwIlAHFuSe6Guoxtd0SRvSfVTDMPd5H+4KE2kKA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -2730,9 +2730,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.0.tgz",
|
||||
"integrity": "sha512-qhFwQ+ljoymC+j5lXRv8DlaJYY/+8vyvYmVx074zrLsu5ZGWYsJNLjPPVJJjhZQpyAKUGPydOq9hRLLNvh1s3A==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.4.tgz",
|
||||
"integrity": "sha512-1aRlh1gqtF7vNPMnlf1vJKk72Yshw5zknR/ZAVh7zycRAGF2XBMVDAHmFQz/Zws5k++nux3LOq/Ejj1WrDR6xg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -2744,9 +2744,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.0.tgz",
|
||||
"integrity": "sha512-44n/X3lAlWsEY6vF8CzgCx+LQaoqWGN7TzUfbJDiTIOjJm4+L2Yq+r5a8ytQRGyPqgJDs3Rgyo8eVL7n9iW6AQ==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.4.tgz",
|
||||
"integrity": "sha512-drHl+4qhFj+PV/jrQ78p9ch6A0MfNVZScl/nBps5a7u01aGf/GuBRrHnRegA9bP222CBDfjYbFdjkIJ/FurvSQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -2758,9 +2758,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.0.tgz",
|
||||
"integrity": "sha512-F9ct0+ZX5Np6+ZDztxiGCIvlCaW87HBdHcozUfsHnj1WCUTBUubAoanhHUfnUHZABlElyRikI0mgcw/qdEm2VQ==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.4.tgz",
|
||||
"integrity": "sha512-hQqq/8QALU6t1+fbNmm6dwYsa0PDD4L5r3TpHx9dNl+aSEMnIksHZkSO3AVH+hBMvZhpumIGrTFj8XCOGuIXjw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -2772,9 +2772,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.0.tgz",
|
||||
"integrity": "sha512-JpsGxLBB2EFXBsTLHfkZDsXSpSmKD3VxXCgBQtlPcuAqB8TlqtLcbeMhxXQkCDv1avgwNjF8uEIbq5p+Cee0PA==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.4.tgz",
|
||||
"integrity": "sha512-/L0LixBmbefkec1JTeAQJP0ETzGjFtNml2gpQXA8rpLo7Md+iXQzo9kwEgzyat5Q+OG/C//2B9Fx52UxsOXbzw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -2786,9 +2786,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.0.tgz",
|
||||
"integrity": "sha512-wegiyBT6rawdpvnD9lmbOpx5Sph+yVZKHbhnSP9MqUEDX08G4UzMU+D87jrazGE7lRSyTRs6NEYHtzfkJ3FjjQ==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.4.tgz",
|
||||
"integrity": "sha512-6Rk3PLRK+b8L/M6m/x6Mfj60LhAUcLJ34oPaxufA+CfqkUrDoUPQYFdRrhqyOvtOKXLJZJwxlOLbQjNYQcRQfw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -2800,9 +2800,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.0.tgz",
|
||||
"integrity": "sha512-3pA7xecItbgOs1A5H58dDvOUEboG5UfpTq3WzAdF54acBbUM+olDJAPkgj1GRJ4ZqE12DZ9/hNS2QZk166v92A==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.4.tgz",
|
||||
"integrity": "sha512-kmT3x0IPRuXY/tNoABp2nDvI9EvdiS2JZsd4I9yOcLCCViKsP0gB38mVHOhluzx+SSVnM1KNn9k6osyXZhLoCA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -2814,9 +2814,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.0.tgz",
|
||||
"integrity": "sha512-Y7XUZEVISGyge51QbYyYAEHwpGgmRrAxQXO3siyYo2kmaj72USSG8LtlQQgAtlGfxYiOwu+2BdbPjzEpcOpRmQ==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.4.tgz",
|
||||
"integrity": "sha512-3iSA9tx+4PZcJH/Wnwsvx/BY4qHpit/u2YoZoXugWVfc36/4mRkgGEoRbRV7nzNBSCOgbWMeuQ27IQWgJ7tRzw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -2828,9 +2828,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.0.tgz",
|
||||
"integrity": "sha512-r7/OTF5MqeBrZo5omPXcTnjvv1GsrdH8a8RerARvDFiDwFpDVDnJyByYM/nX+mvks8XXsgPUxkwe/ltaX2VH7w==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.4.tgz",
|
||||
"integrity": "sha512-7CwSJW+sEhM9sESEk+pEREF2JL0BmyCro8UyTq0Kyh0nu1v0QPNY3yfLPFKChzVoUmaKj8zbdgBxUhBRR+xGxg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -2842,9 +2842,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.0.tgz",
|
||||
"integrity": "sha512-HJbifC9vex9NqnlodV2BHVFNuzKL5OnsV2dvTw6e1dpZKkNjPG6WUq+nhEYV6Hv2Bv++BXkwcyoGlXnPrjAKXw==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.4.tgz",
|
||||
"integrity": "sha512-GZdafB41/4s12j8Ss2izofjeFXRAAM7sHCb+S4JsI9vaONX/zQ8cXd87B9MRU/igGAJkKvmFmJJBeeT9jJ5Cbw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -2856,9 +2856,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.0.tgz",
|
||||
"integrity": "sha512-VAEzZTD63YglFlWwRj3taofmkV1V3xhebDXffon7msNz4b14xKsz7utO6F8F4cqt8K/ktTl9rm88yryvDpsfOw==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.4.tgz",
|
||||
"integrity": "sha512-uuphLuw1X6ur11675c2twC6YxbzyLSpWggvdawTUamlsoUv81aAXRMPBC1uvQllnBGls0Qt5Siw8reSIBnbdqQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
|
@ -2870,9 +2870,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.0.tgz",
|
||||
"integrity": "sha512-Sts5DST1jXAc9YH/iik1C9QRsLcCoOScf3dfbY5i4kH9RJpKxiTBXqm7qU5O6zTXBTEZry69bGszr3SMgYmMcQ==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.4.tgz",
|
||||
"integrity": "sha512-KvLEw1os2gSmD6k6QPCQMm2T9P2GYvsMZMRpMz78QpSoEevHbV/KOUbI/46/JRalhtSAYZBYLAnT9YE4i/l4vg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
@ -2884,9 +2884,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.0.tgz",
|
||||
"integrity": "sha512-qhlXeV9AqxIyY9/R1h1hBD6eMvQCO34ZmdYvry/K+/MBs6d1nRFLm6BOiITLVI+nFAAB9kUB6sdJRKyVHXnqZw==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.4.tgz",
|
||||
"integrity": "sha512-wcpCLHGM9yv+3Dql/CI4zrY2mpQ4WFergD3c9cpRowltEh5I84pRT/EuHZsG0In4eBPPYthXnuR++HrFkeqwkA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
@ -2898,9 +2898,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.0.tgz",
|
||||
"integrity": "sha512-8ZGN7ExnV0qjXa155Rsfi6H8M4iBBwNLBM9lcVS+4NcSzOFaNqmt7djlox8pN1lWrRPMRRQ8NeDlozIGx3Omsw==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.4.tgz",
|
||||
"integrity": "sha512-nLbfQp2lbJYU8obhRQusXKbuiqm4jSJteLwfjnunDT5ugBKdxqw1X9KWwk8xp1OMC6P5d0WbzxzhWoznuVK6XA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
@ -2912,9 +2912,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.0.tgz",
|
||||
"integrity": "sha512-VDzNHtLLI5s7xd/VubyS10mq6TxvZBp+4NRWoW+Hi3tgV05RtVm4qK99+dClwTN1McA6PHwob6DEJ6PlXbY83A==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.4.tgz",
|
||||
"integrity": "sha512-JGejzEfVzqc/XNiCKZj14eb6s5w8DdWlnQ5tWUbs99kkdvfq9btxxVX97AaxiUX7xJTKFA0LwoS0KU8C2faZRg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -2926,9 +2926,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.0.tgz",
|
||||
"integrity": "sha512-qcb9qYDlkxz9DxJo7SDhWxTWV1gFuwznjbTiov289pASxlfGbaOD54mgbs9+z94VwrXtKTu+2RqwlSTbiOqxGg==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.4.tgz",
|
||||
"integrity": "sha512-/iFIbhzeyZZy49ozAWJ1ZR2KW6ZdYUbQXLT4O5n1cRZRoTpwExnHLjlurDXXPKEGxiAg0ujaR9JDYKljpr2fDg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -2940,9 +2940,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.0.tgz",
|
||||
"integrity": "sha512-pFDdotFDMXW2AXVbfdUEfidPAk/OtwE/Hd4eYMTNVVaCQ6Yl8et0meDaKNL63L44Haxv4UExpv9ydSf3aSayDg==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.4.tgz",
|
||||
"integrity": "sha512-qORc3UzoD5UUTneiP2Afg5n5Ti1GAW9Gp5vHPxzvAFFA3FBaum9WqGvYXGf+c7beFdOKNos31/41PRMUwh1tpA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -2954,9 +2954,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.0.tgz",
|
||||
"integrity": "sha512-/TG7WfrCAjeRNDvI4+0AAMoHxea/USWhAzf9PVDFHbcqrQ7hMMKp4jZIy4VEjk72AAfN5k4TiSMRXRKf/0akSw==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.4.tgz",
|
||||
"integrity": "sha512-5g7E2PHNK2uvoD5bASBD9aelm44nf1w4I5FEI7MPHLWcCSrR8JragXZWgKPXk5i2FU3JFfa6CGZLw2RrGBHs2Q==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
@ -2968,9 +2968,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.0.tgz",
|
||||
"integrity": "sha512-5hqO5S3PTEO2E5VjCePxv40gIgyS2KvO7E7/vvC/NbIW4SIRamkMr1hqj+5Y67fbBWv/bQLB6KelBQmXlyCjWA==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.4.tgz",
|
||||
"integrity": "sha512-p0scwGkR4kZ242xLPBuhSckrJ734frz6v9xZzD+kHVYRAkSUmdSLCIJRfql6H5//aF8Q10K+i7q8DiPfZp0b7A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -3009,9 +3009,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.64.2",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.64.2.tgz",
|
||||
"integrity": "sha512-hdO8SZpWXoADNTWXV9We8CwTkXU88OVWRBcsiFrk7xJQnhm6WRlweDzMD+uH+GnuieTBVSML6xFa17C2cNV8+g==",
|
||||
"version": "5.66.0",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.66.0.tgz",
|
||||
"integrity": "sha512-J+JeBtthiKxrpzUu7rfIPDzhscXF2p5zE/hVdrqkACBP8Yu0M96mwJ5m/8cPPYQE9aRNvXztXHlNwIh4FEeMZw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
|
@ -3019,9 +3019,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-devtools": {
|
||||
"version": "5.64.2",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.64.2.tgz",
|
||||
"integrity": "sha512-3DautR5UpVZdk/qNIhioZVF7g8fdQZ1U98sBEEk4Tzz3tihSBNMPgwlP40nzgbPEDBIrn/j/oyyvNBVSo083Vw==",
|
||||
"version": "5.65.0",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.65.0.tgz",
|
||||
"integrity": "sha512-g5y7zc07U9D3esMdqUfTEVu9kMHoIaVBsD0+M3LPdAdD710RpTcLiNvJY1JkYXqkq9+NV+CQoemVNpQPBXVsJg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
|
@ -3029,12 +3029,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "5.64.2",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.64.2.tgz",
|
||||
"integrity": "sha512-3pakNscZNm8KJkxmovvtZ4RaXLyiYYobwleTMvpIGUoKRa8j8VlrQKNl5W8VUEfVfZKkikvXVddLuWMbcSCA1Q==",
|
||||
"version": "5.66.0",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.66.0.tgz",
|
||||
"integrity": "sha512-z3sYixFQJe8hndFnXgWu7C79ctL+pI0KAelYyW+khaNJ1m22lWrhJU2QrsTcRKMuVPtoZvfBYrTStIdKo+x0Xw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.64.2"
|
||||
"@tanstack/query-core": "5.66.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
|
@ -3045,19 +3045,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query-devtools": {
|
||||
"version": "5.64.2",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.64.2.tgz",
|
||||
"integrity": "sha512-+ZjJVnPzc8BUV/Eklu2k9T/IAyAyvwoCHqOaOrk2sbU33LFhM52BpX4eyENXn0bx5LwV3DJZgEQlIzucoemfGQ==",
|
||||
"version": "5.66.0",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.66.0.tgz",
|
||||
"integrity": "sha512-uB57wA2YZaQ2fPcFW0E9O1zAGDGSbRKRx84uMk/86VyU9jWVxvJ3Uzp+zNm+nZJYsuekCIo2opTdgNuvM3cKgA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tanstack/query-devtools": "5.64.2"
|
||||
"@tanstack/query-devtools": "5.65.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tanstack/react-query": "^5.64.2",
|
||||
"@tanstack/react-query": "^5.66.0",
|
||||
"react": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
|
@ -3308,9 +3308,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/d3-path": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz",
|
||||
"integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
|
||||
"integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/d3-polygon": {
|
||||
|
@ -3332,9 +3332,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/d3-scale": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz",
|
||||
"integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==",
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
|
||||
"integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/d3-time": "*"
|
||||
|
@ -3477,9 +3477,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.10.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz",
|
||||
"integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==",
|
||||
"version": "22.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz",
|
||||
"integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -3545,21 +3545,21 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.21.0.tgz",
|
||||
"integrity": "sha512-eTH+UOR4I7WbdQnG4Z48ebIA6Bgi7WO8HvFEneeYBxG8qCOYgTOFPSg6ek9ITIDvGjDQzWHcoWHCDO2biByNzA==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz",
|
||||
"integrity": "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.21.0",
|
||||
"@typescript-eslint/type-utils": "8.21.0",
|
||||
"@typescript-eslint/utils": "8.21.0",
|
||||
"@typescript-eslint/visitor-keys": "8.21.0",
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/type-utils": "8.23.0",
|
||||
"@typescript-eslint/utils": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.0.0"
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -3575,16 +3575,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.21.0.tgz",
|
||||
"integrity": "sha512-Wy+/sdEH9kI3w9civgACwabHbKl+qIOu0uFZ9IMKzX3Jpv9og0ZBJrZExGrPpFAY7rWsXuxs5e7CPPP17A4eYA==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.23.0.tgz",
|
||||
"integrity": "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.21.0",
|
||||
"@typescript-eslint/types": "8.21.0",
|
||||
"@typescript-eslint/typescript-estree": "8.21.0",
|
||||
"@typescript-eslint/visitor-keys": "8.21.0",
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/typescript-estree": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -3600,14 +3600,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.21.0.tgz",
|
||||
"integrity": "sha512-G3IBKz0/0IPfdeGRMbp+4rbjfSSdnGkXsM/pFZA8zM9t9klXDnB/YnKOBQ0GoPmoROa4bCq2NeHgJa5ydsQ4mA==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.23.0.tgz",
|
||||
"integrity": "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.21.0",
|
||||
"@typescript-eslint/visitor-keys": "8.21.0"
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -3618,16 +3618,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.21.0.tgz",
|
||||
"integrity": "sha512-95OsL6J2BtzoBxHicoXHxgk3z+9P3BEcQTpBKriqiYzLKnM2DeSqs+sndMKdamU8FosiadQFT3D+BSL9EKnAJQ==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.23.0.tgz",
|
||||
"integrity": "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.21.0",
|
||||
"@typescript-eslint/utils": "8.21.0",
|
||||
"@typescript-eslint/typescript-estree": "8.23.0",
|
||||
"@typescript-eslint/utils": "8.23.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.0.0"
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -3642,9 +3642,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.21.0.tgz",
|
||||
"integrity": "sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz",
|
||||
"integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
@ -3656,20 +3656,20 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.21.0.tgz",
|
||||
"integrity": "sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz",
|
||||
"integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.21.0",
|
||||
"@typescript-eslint/visitor-keys": "8.21.0",
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^2.0.0"
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -3683,16 +3683,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.21.0.tgz",
|
||||
"integrity": "sha512-xcXBfcq0Kaxgj7dwejMbFyq7IOHgpNMtVuDveK7w3ZGwG9owKzhALVwKpTF2yrZmEwl9SWdetf3fxNzJQaVuxw==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.23.0.tgz",
|
||||
"integrity": "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.21.0",
|
||||
"@typescript-eslint/types": "8.21.0",
|
||||
"@typescript-eslint/typescript-estree": "8.21.0"
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/typescript-estree": "8.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -3707,13 +3707,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.21.0.tgz",
|
||||
"integrity": "sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz",
|
||||
"integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.21.0",
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -3738,9 +3738,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@uiw/codemirror-extensions-basic-setup": {
|
||||
"version": "4.23.7",
|
||||
"resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.23.7.tgz",
|
||||
"integrity": "sha512-9/2EUa1Lck4kFKkR2BkxlZPpgD/EWuKHnOlysf1yHKZGraaZmZEaUw+utDK4QcuJc8Iz097vsLz4f4th5EU27g==",
|
||||
"version": "4.23.8",
|
||||
"resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.23.8.tgz",
|
||||
"integrity": "sha512-XJR/8AEVcE7ufy1BhW2nCN9qSVDYEdCtYLfvhaMwl6Q3qcaYYCGE2K5QbFCy7LsdP/3uZKvc1OskuqatoOPdhQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.0.0",
|
||||
|
@ -3765,9 +3765,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@uiw/codemirror-themes": {
|
||||
"version": "4.23.7",
|
||||
"resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.23.7.tgz",
|
||||
"integrity": "sha512-UNf1XOx1hG9OmJnrtT86PxKcdcwhaNhbrcD+nsk8WxRJ3n5c8nH6euDvgVPdVLPwbizsaQcZTILACgA/FjRpVg==",
|
||||
"version": "4.23.8",
|
||||
"resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.23.8.tgz",
|
||||
"integrity": "sha512-PZmJBZxWMuZ48p/2D5aRPl8zTlBq1d/+NeRqyyH6P6k6yWDF6h71m0Dt+fjslgPE7KmWXux2hbejXXXoRLZO9Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/language": "^6.0.0",
|
||||
|
@ -3784,16 +3784,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@uiw/react-codemirror": {
|
||||
"version": "4.23.7",
|
||||
"resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.23.7.tgz",
|
||||
"integrity": "sha512-Nh/0P6W+kWta+ARp9YpnKPD9ick5teEnwmtNoPQnyd6NPv0EQP3Ui4YmRVNj1nkUEo+QjrAUaEfcejJ2up/HZA==",
|
||||
"version": "4.23.8",
|
||||
"resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.23.8.tgz",
|
||||
"integrity": "sha512-/NA5Pj4MmXkLSlmlUm4yfEmRLntrNq5TkQKBSINn7TukXQ4fc+C6Bk0U60Qa4rkvCSgwzZdQ2exyP0t0+2GtqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.6",
|
||||
"@codemirror/commands": "^6.1.0",
|
||||
"@codemirror/state": "^6.1.1",
|
||||
"@codemirror/theme-one-dark": "^6.0.0",
|
||||
"@uiw/codemirror-extensions-basic-setup": "4.23.7",
|
||||
"@uiw/codemirror-extensions-basic-setup": "4.23.8",
|
||||
"codemirror": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
|
@ -4288,9 +4288,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/babel-plugin-react-compiler": {
|
||||
"version": "19.0.0-beta-e552027-20250112",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-e552027-20250112.tgz",
|
||||
"integrity": "sha512-pUTT0mAZ4XLewC6bvqVeX015nVRLVultcSQlkzGdC10G6YV6K2h4E7cwGlLAuLKWTj3Z08mTO9uTnPP/opUBsg==",
|
||||
"version": "19.0.0-beta-714736e-20250131",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-714736e-20250131.tgz",
|
||||
"integrity": "sha512-frj2l6fRWVi26iw9WthFKyFyE4u5ZSHH3KdKiscOOwpz210seTtwnp0QbJmi8Zoa5HK7Fk2fH40JffN2y8GvLg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -4527,9 +4527,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001695",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
|
||||
"integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
|
||||
"version": "1.0.30001697",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001697.tgz",
|
||||
"integrity": "sha512-GwNPlWJin8E+d7Gxq96jxM6w0w+VFeyyXRsjU58emtkYqnbwHqXm5uT2uCmO0RQE9htWknOP4xtBlLmM/gWxvQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4629,9 +4629,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/cjs-module-lexer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz",
|
||||
"integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==",
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
|
||||
"integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
@ -5211,9 +5211,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.88",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.88.tgz",
|
||||
"integrity": "sha512-K3C2qf1o+bGzbilTDCTBhTQcMS9KW60yTAaTeeXsfvQuTDDwlokLam/AdqlqcSy9u4UainDgsHV23ksXAOgamw==",
|
||||
"version": "1.5.93",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.93.tgz",
|
||||
"integrity": "sha512-M+29jTcfNNoR9NV7la4SwUqzWAxEwnc7ThA5e1m6LRSotmpfpCpLcIfgtSCVL+MllNLgAyM/5ru86iMRemPzDQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
|
@ -5574,9 +5574,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react-compiler": {
|
||||
"version": "19.0.0-beta-e552027-20250112",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-e552027-20250112.tgz",
|
||||
"integrity": "sha512-VjkIXHouCYyJHgk5HmZ1LH+fAK5CX+ULRX9iNYtwYJ+ljbivFhIT+JJyxNT/USQpCeS2Dt5ahjFeeMv0RRwTww==",
|
||||
"version": "19.0.0-beta-714736e-20250131",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-714736e-20250131.tgz",
|
||||
"integrity": "sha512-iTPUaHzvBejGqicSwZLCDBgWBxLzU1Dvqjs31loNoOPRnsey5dcOupaZajECKVvXmB1wcbIWNp6/VR5+dM9d6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -5911,9 +5911,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.18.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
|
||||
"integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
|
||||
"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
|
@ -6554,9 +6554,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parent-module": "^1.0.0",
|
||||
|
@ -6719,13 +6719,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/is-boolean-object": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz",
|
||||
"integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
|
||||
"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"call-bound": "^1.0.3",
|
||||
"has-tostringtag": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -7042,13 +7042,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/is-weakref": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz",
|
||||
"integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
|
||||
"integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2"
|
||||
"call-bound": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
|
@ -8306,9 +8306,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
|
||||
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
@ -8721,13 +8721,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.50.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.0.tgz",
|
||||
"integrity": "sha512-+GinGfGTrd2IfX1TA4N2gNmeIksSb+IAe589ZH+FlmpV3MYTx6+buChGIuDLQwrGNCw2lWibqV50fU510N7S+w==",
|
||||
"version": "1.50.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz",
|
||||
"integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.50.0"
|
||||
"playwright-core": "1.50.1"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
|
@ -8740,9 +8740,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.50.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.0.tgz",
|
||||
"integrity": "sha512-CXkSSlr4JaZs2tZHI40DsZUN/NIwgaUPsyLuOAaIZp2CyF2sN5MM5NJsyB188lFSSozFxQ5fPT4qM+f0tH/6wQ==",
|
||||
"version": "1.50.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz",
|
||||
"integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
|
@ -9181,9 +9181,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.3.tgz",
|
||||
"integrity": "sha512-EezYymLY6Guk/zLQ2vRA8WvdUhWFEj5fcE3RfWihhxXBW7+cd1LsIiA3lmx+KCmneAGQuyBv820o44L2+TtkSA==",
|
||||
"version": "7.1.5",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.5.tgz",
|
||||
"integrity": "sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.6.0",
|
||||
|
@ -9282,9 +9282,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-zoom-pan-pinch": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.6.1.tgz",
|
||||
"integrity": "sha512-SdPqdk7QDSV7u/WulkFOi+cnza8rEZ0XX4ZpeH7vx3UZEg7DoyuAy3MCmm+BWv/idPQL2Oe73VoC0EhfCN+sZQ==",
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.7.0.tgz",
|
||||
"integrity": "sha512-UmReVZ0TxlKzxSbYiAj+LeGRW8s8LraAFTXRAxzMYnNRgGPsxCudwZKVkjvGmjtx7SW/hZamt69NUmGf4xrkXA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
|
@ -9468,9 +9468,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.32.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.0.tgz",
|
||||
"integrity": "sha512-JmrhfQR31Q4AuNBjjAX4s+a/Pu/Q8Q9iwjWBsjRH1q52SPFE2NqRMK6fUZKKnvKO6id+h7JIRf0oYsph53eATg==",
|
||||
"version": "4.34.4",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.4.tgz",
|
||||
"integrity": "sha512-spF66xoyD7rz3o08sHP7wogp1gZ6itSq22SGa/IZTcUDXDlOyrShwMwkVSB+BUxFRZZCUYqdb3KWDEOMVQZxuw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -9484,25 +9484,25 @@
|
|||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.32.0",
|
||||
"@rollup/rollup-android-arm64": "4.32.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.32.0",
|
||||
"@rollup/rollup-darwin-x64": "4.32.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.32.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.32.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.32.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.32.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.32.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.32.0",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.32.0",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.32.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.32.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.32.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.32.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.32.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.32.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.32.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.32.0",
|
||||
"@rollup/rollup-android-arm-eabi": "4.34.4",
|
||||
"@rollup/rollup-android-arm64": "4.34.4",
|
||||
"@rollup/rollup-darwin-arm64": "4.34.4",
|
||||
"@rollup/rollup-darwin-x64": "4.34.4",
|
||||
"@rollup/rollup-freebsd-arm64": "4.34.4",
|
||||
"@rollup/rollup-freebsd-x64": "4.34.4",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.34.4",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.34.4",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.34.4",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.34.4",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.34.4",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.4",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.34.4",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.34.4",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.34.4",
|
||||
"@rollup/rollup-linux-x64-musl": "4.34.4",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.34.4",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.34.4",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.34.4",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
|
@ -9592,9 +9592,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
|
@ -10269,9 +10269,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz",
|
||||
"integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
@ -10478,15 +10478,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.21.0.tgz",
|
||||
"integrity": "sha512-txEKYY4XMKwPXxNkN8+AxAdX6iIJAPiJbHE/FpQccs/sxw8Lf26kqwC3cn0xkHlW8kEbLhkhCsjWuMveaY9Rxw==",
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.23.0.tgz",
|
||||
"integrity": "sha512-/LBRo3HrXr5LxmrdYSOCvoAMm7p2jNizNfbIpCgvG4HMsnoprRUOce/+8VJ9BDYWW68rqIENE/haVLWPeFZBVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.21.0",
|
||||
"@typescript-eslint/parser": "8.21.0",
|
||||
"@typescript-eslint/utils": "8.21.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.23.0",
|
||||
"@typescript-eslint/parser": "8.23.0",
|
||||
"@typescript-eslint/utils": "8.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
@ -10625,15 +10625,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.0.11",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
|
||||
"integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
|
||||
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.24.2",
|
||||
"postcss": "^8.4.49",
|
||||
"rollup": "^4.23.0"
|
||||
"postcss": "^8.5.1",
|
||||
"rollup": "^4.30.1"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
"@dagrejs/dagre": "^1.1.4",
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@lezer/lr": "^1.4.2",
|
||||
"@tanstack/react-query": "^5.64.2",
|
||||
"@tanstack/react-query-devtools": "^5.64.2",
|
||||
"@tanstack/react-query": "^5.66.0",
|
||||
"@tanstack/react-query-devtools": "^5.66.0",
|
||||
"@tanstack/react-table": "^8.20.6",
|
||||
"@uiw/codemirror-themes": "^4.23.7",
|
||||
"@uiw/react-codemirror": "^4.23.7",
|
||||
"@uiw/codemirror-themes": "^4.23.8",
|
||||
"@uiw/react-codemirror": "^4.23.8",
|
||||
"axios": "^1.7.9",
|
||||
"clsx": "^2.1.1",
|
||||
"html-to-image": "^1.11.11",
|
||||
|
@ -31,12 +31,12 @@
|
|||
"react-hook-form": "^7.54.2",
|
||||
"react-icons": "^5.4.0",
|
||||
"react-intl": "^7.1.5",
|
||||
"react-router": "^7.1.3",
|
||||
"react-router": "^7.1.5",
|
||||
"react-select": "^5.10.0",
|
||||
"react-tabs": "^6.1.0",
|
||||
"react-toastify": "^11.0.3",
|
||||
"react-tooltip": "^5.28.0",
|
||||
"react-zoom-pan-pinch": "^3.6.1",
|
||||
"react-zoom-pan-pinch": "^3.7.0",
|
||||
"reactflow": "^11.11.4",
|
||||
"use-debounce": "^10.0.4",
|
||||
"zod": "^3.24.1",
|
||||
|
@ -44,9 +44,9 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@lezer/generator": "^1.7.2",
|
||||
"@playwright/test": "^1.50.0",
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.10.10",
|
||||
"@types/node": "^22.13.1",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.1",
|
||||
|
@ -65,8 +65,8 @@
|
|||
"tailwindcss": "^3.4.17",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.21.0",
|
||||
"vite": "^6.0.11"
|
||||
"typescript-eslint": "^8.23.0",
|
||||
"vite": "^6.1.0"
|
||||
},
|
||||
"overrides": {
|
||||
"react": "^19.0.0"
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { Suspense } from 'react';
|
||||
import { Outlet } from 'react-router';
|
||||
|
||||
import ConceptToaster from '@/app/ConceptToaster';
|
||||
import Footer from '@/app/Footer';
|
||||
import Navigation from '@/app/Navigation';
|
||||
import Loader from '@/components/ui/Loader';
|
||||
import ModalLoader from '@/components/ui/ModalLoader';
|
||||
import { Loader } from '@/components/Loader';
|
||||
import { ModalLoader } from '@/components/Modal';
|
||||
import { useAppLayoutStore, useMainHeight, useViewportHeight } from '@/stores/appLayout';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { Footer } from './Footer';
|
||||
import { GlobalDialogs } from './GlobalDialogs';
|
||||
import ConceptToaster from './GlobalToaster';
|
||||
import { GlobalTooltips } from './GlobalTooltips';
|
||||
import { Navigation } from './Navigation';
|
||||
import { NavigationState } from './Navigation/NavigationContext';
|
||||
|
||||
function ApplicationLayout() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { useNavigate, useRouteError } from 'react-router';
|
||||
|
||||
import InfoError from '@/components/info/InfoError';
|
||||
import Button from '@/components/ui/Button';
|
||||
import { Button } from '@/components/Control';
|
||||
import { InfoError } from '@/components/InfoError';
|
||||
|
||||
function ErrorFallback() {
|
||||
export function ErrorFallback() {
|
||||
const error = useRouteError();
|
||||
const router = useNavigate();
|
||||
|
||||
|
@ -18,5 +18,3 @@ function ErrorFallback() {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ErrorFallback;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import TextURL from '@/components/ui/TextURL';
|
||||
import { TextURL } from '@/components/Control';
|
||||
import { external_urls } from '@/utils/constants';
|
||||
|
||||
function Footer() {
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer
|
||||
className={clsx(
|
||||
|
@ -25,5 +25,3 @@ function Footer() {
|
|||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
export default Footer;
|
||||
|
|
|
@ -2,32 +2,31 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { DialogType } from '@/models/miscellaneous';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
import { DialogType, useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
const DlgChangeInputSchema = React.lazy(() => import('@/dialogs/DlgChangeInputSchema'));
|
||||
const DlgChangeLocation = React.lazy(() => import('@/dialogs/DlgChangeLocation'));
|
||||
const DlgCloneLibraryItem = React.lazy(() => import('@/dialogs/DlgCloneLibraryItem'));
|
||||
const DlgCreateCst = React.lazy(() => import('@/dialogs/DlgCreateCst'));
|
||||
const DlgCreateOperation = React.lazy(() => import('@/dialogs/DlgCreateOperation'));
|
||||
const DlgCreateVersion = React.lazy(() => import('@/dialogs/DlgCreateVersion'));
|
||||
const DlgCstTemplate = React.lazy(() => import('@/dialogs/DlgCstTemplate'));
|
||||
const DlgDeleteCst = React.lazy(() => import('@/dialogs/DlgDeleteCst'));
|
||||
const DlgDeleteOperation = React.lazy(() => import('@/dialogs/DlgDeleteOperation'));
|
||||
const DlgEditEditors = React.lazy(() => import('@/dialogs/DlgEditEditors'));
|
||||
const DlgEditOperation = React.lazy(() => import('@/dialogs/DlgEditOperation'));
|
||||
const DlgEditReference = React.lazy(() => import('@/dialogs/DlgEditReference'));
|
||||
const DlgEditVersions = React.lazy(() => import('@/dialogs/DlgEditVersions'));
|
||||
const DlgEditWordForms = React.lazy(() => import('@/dialogs/DlgEditWordForms'));
|
||||
const DlgGraphParams = React.lazy(() => import('@/dialogs/DlgGraphParams'));
|
||||
const DlgInlineSynthesis = React.lazy(() => import('@/dialogs/DlgInlineSynthesis'));
|
||||
const DlgRelocateConstituents = React.lazy(() => import('@/dialogs/DlgRelocateConstituents'));
|
||||
const DlgRenameCst = React.lazy(() => import('@/dialogs/DlgRenameCst'));
|
||||
const DlgShowAST = React.lazy(() => import('@/dialogs/DlgShowAST'));
|
||||
const DlgShowQR = React.lazy(() => import('@/dialogs/DlgShowQR'));
|
||||
const DlgShowTypeGraph = React.lazy(() => import('@/dialogs/DlgShowTypeGraph'));
|
||||
const DlgSubstituteCst = React.lazy(() => import('@/dialogs/DlgSubstituteCst'));
|
||||
const DlgUploadRSForm = React.lazy(() => import('@/dialogs/DlgUploadRSForm'));
|
||||
const DlgChangeInputSchema = React.lazy(() => import('@/features/oss/dialogs/DlgChangeInputSchema'));
|
||||
const DlgChangeLocation = React.lazy(() => import('@/features/library/dialogs/DlgChangeLocation'));
|
||||
const DlgCloneLibraryItem = React.lazy(() => import('@/features/rsform/dialogs/DlgCloneLibraryItem'));
|
||||
const DlgCreateCst = React.lazy(() => import('@/features/rsform/dialogs/DlgCreateCst'));
|
||||
const DlgCreateOperation = React.lazy(() => import('@/features/oss/dialogs/DlgCreateOperation'));
|
||||
const DlgCreateVersion = React.lazy(() => import('@/features/rsform/dialogs/DlgCreateVersion'));
|
||||
const DlgCstTemplate = React.lazy(() => import('@/features/rsform/dialogs/DlgCstTemplate'));
|
||||
const DlgDeleteCst = React.lazy(() => import('@/features/rsform/dialogs/DlgDeleteCst'));
|
||||
const DlgDeleteOperation = React.lazy(() => import('@/features/oss/dialogs/DlgDeleteOperation'));
|
||||
const DlgEditEditors = React.lazy(() => import('@/features/library/dialogs/DlgEditEditors'));
|
||||
const DlgEditOperation = React.lazy(() => import('@/features/oss/dialogs/DlgEditOperation'));
|
||||
const DlgEditReference = React.lazy(() => import('@/features/rsform/dialogs/DlgEditReference'));
|
||||
const DlgEditVersions = React.lazy(() => import('@/features/rsform/dialogs/DlgEditVersions'));
|
||||
const DlgEditWordForms = React.lazy(() => import('@/features/rsform/dialogs/DlgEditWordForms'));
|
||||
const DlgGraphParams = React.lazy(() => import('@/features/rsform/dialogs/DlgGraphParams'));
|
||||
const DlgInlineSynthesis = React.lazy(() => import('@/features/rsform/dialogs/DlgInlineSynthesis'));
|
||||
const DlgRelocateConstituents = React.lazy(() => import('@/features/oss/dialogs/DlgRelocateConstituents'));
|
||||
const DlgRenameCst = React.lazy(() => import('@/features/rsform/dialogs/DlgRenameCst'));
|
||||
const DlgShowAST = React.lazy(() => import('@/features/rsform/dialogs/DlgShowAST'));
|
||||
const DlgShowQR = React.lazy(() => import('@/features/rsform/dialogs/DlgShowQR'));
|
||||
const DlgShowTypeGraph = React.lazy(() => import('@/features/rsform/dialogs/DlgShowTypeGraph'));
|
||||
const DlgSubstituteCst = React.lazy(() => import('@/features/rsform/dialogs/DlgSubstituteCst'));
|
||||
const DlgUploadRSForm = React.lazy(() => import('@/features/rsform/dialogs/DlgUploadRSForm'));
|
||||
|
||||
export const GlobalDialogs = () => {
|
||||
const active = useDialogsStore(state => state.active);
|
||||
|
|
|
@ -6,7 +6,6 @@ interface ToasterThemedProps extends Omit<ToastContainerProps, 'theme'> {}
|
|||
|
||||
function ToasterThemed(props: ToasterThemedProps) {
|
||||
const darkMode = usePreferencesStore(state => state.darkMode);
|
||||
|
||||
return <ToastContainer theme={darkMode ? 'dark' : 'light'} {...props} />;
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
'use client';
|
||||
|
||||
import InfoConstituenta from '@/components/info/InfoConstituenta';
|
||||
import Loader from '@/components/ui/Loader';
|
||||
import Tooltip from '@/components/ui/Tooltip';
|
||||
import { Tooltip } from '@/components/Container';
|
||||
import { Loader } from '@/components/Loader';
|
||||
import InfoConstituenta from '@/features/rsform/components/InfoConstituenta';
|
||||
import { useTooltipsStore } from '@/stores/tooltips';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { useConceptNavigation } from '@/app/Navigation/NavigationContext';
|
||||
import { IconLibrary2, IconManuals, IconNewItem2 } from '@/components/Icons';
|
||||
import { CProps } from '@/components/props';
|
||||
import useWindowSize from '@/hooks/useWindowSize';
|
||||
|
@ -10,10 +9,11 @@ import { PARAMETER } from '@/utils/constants';
|
|||
import { urls } from '../urls';
|
||||
import Logo from './Logo';
|
||||
import NavigationButton from './NavigationButton';
|
||||
import { useConceptNavigation } from './NavigationContext';
|
||||
import ToggleNavigation from './ToggleNavigation';
|
||||
import UserMenu from './UserMenu';
|
||||
|
||||
function Navigation() {
|
||||
export function Navigation() {
|
||||
const router = useConceptNavigation();
|
||||
const size = useWindowSize();
|
||||
const noNavigationAnimation = useAppLayoutStore(state => state.noNavigationAnimation);
|
||||
|
@ -65,5 +65,3 @@ function Navigation() {
|
|||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
export default Navigation;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useAuthSuspense } from '@/backend/auth/useAuth';
|
||||
import { IconLogin, IconUser2 } from '@/components/Icons';
|
||||
import { useAuthSuspense } from '@/features/auth/backend/useAuth';
|
||||
import { usePreferencesStore } from '@/stores/preferences';
|
||||
|
||||
import NavigationButton from './NavigationButton';
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { useConceptNavigation } from '@/app/Navigation/NavigationContext';
|
||||
import { useAuthSuspense } from '@/backend/auth/useAuth';
|
||||
import { useLogout } from '@/backend/auth/useLogout';
|
||||
import { Dropdown, DropdownButton } from '@/components/Dropdown';
|
||||
import {
|
||||
IconAdmin,
|
||||
IconAdminOff,
|
||||
|
@ -16,11 +14,12 @@ import {
|
|||
IconUser
|
||||
} from '@/components/Icons';
|
||||
import { CProps } from '@/components/props';
|
||||
import Dropdown from '@/components/ui/Dropdown';
|
||||
import DropdownButton from '@/components/ui/DropdownButton';
|
||||
import { useAuthSuspense } from '@/features/auth/backend/useAuth';
|
||||
import { useLogout } from '@/features/auth/backend/useLogout';
|
||||
import { usePreferencesStore } from '@/stores/preferences';
|
||||
|
||||
import { urls } from '../urls';
|
||||
import { useConceptNavigation } from './NavigationContext';
|
||||
|
||||
interface UserDropdownProps {
|
||||
isOpen: boolean;
|
||||
|
@ -46,12 +45,12 @@ function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
|
|||
|
||||
function logoutAndRedirect() {
|
||||
hideDropdown();
|
||||
logout(() => router.push(urls.login));
|
||||
void logout().then(() => router.push(urls.login));
|
||||
}
|
||||
|
||||
function gotoAdmin() {
|
||||
hideDropdown();
|
||||
logout(() => router.push(urls.admin, true));
|
||||
void logout().then(() => router.push(urls.admin, true));
|
||||
}
|
||||
|
||||
function gotoIcons(event: CProps.EventMouse) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Suspense } from 'react';
|
||||
|
||||
import { useConceptNavigation } from '@/app/Navigation/NavigationContext';
|
||||
import Loader from '@/components/ui/Loader';
|
||||
import useDropdown from '@/hooks/useDropdown';
|
||||
import { useDropdown } from '@/components/Dropdown';
|
||||
import { Loader } from '@/components/Loader';
|
||||
|
||||
import { urls } from '../urls';
|
||||
import { useConceptNavigation } from './NavigationContext';
|
||||
import UserButton from './UserButton';
|
||||
import UserDropdown from './UserDropdown';
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
export { default } from './Navigation';
|
||||
export { Navigation } from './Navigation';
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import { createBrowserRouter } from 'react-router';
|
||||
|
||||
import { prefetchAuth } from '@/backend/auth/useAuth';
|
||||
import { prefetchLibrary } from '@/backend/library/useLibrary';
|
||||
import { prefetchOSS } from '@/backend/oss/useOSS';
|
||||
import { prefetchRSForm } from '@/backend/rsform/useRSForm';
|
||||
import { prefetchProfile } from '@/backend/users/useProfile';
|
||||
import { prefetchUsers } from '@/backend/users/useUsers';
|
||||
import Loader from '@/components/ui/Loader';
|
||||
import CreateItemPage from '@/pages/CreateItemPage';
|
||||
import HomePage from '@/pages/HomePage';
|
||||
import LoginPage from '@/pages/LoginPage';
|
||||
import NotFoundPage from '@/pages/NotFoundPage';
|
||||
import { Loader } from '@/components/Loader';
|
||||
import { prefetchAuth } from '@/features/auth/backend/useAuth';
|
||||
import LoginPage from '@/features/auth/pages/LoginPage';
|
||||
import HomePage from '@/features/home/HomePage';
|
||||
import NotFoundPage from '@/features/home/NotFoundPage';
|
||||
import { prefetchLibrary } from '@/features/library/backend/useLibrary';
|
||||
import CreateItemPage from '@/features/library/pages/CreateItemPage';
|
||||
import { prefetchOSS } from '@/features/oss/backend/useOSS';
|
||||
import { prefetchRSForm } from '@/features/rsform/backend/useRSForm';
|
||||
import { prefetchProfile } from '@/features/users/backend/useProfile';
|
||||
import { prefetchUsers } from '@/features/users/backend/useUsers';
|
||||
|
||||
import ApplicationLayout from './ApplicationLayout';
|
||||
import ErrorFallback from './ErrorFallback';
|
||||
import { ErrorFallback } from './ErrorFallback';
|
||||
import { routes } from './urls';
|
||||
|
||||
export const Router = createBrowserRouter([
|
||||
|
@ -38,25 +38,25 @@ export const Router = createBrowserRouter([
|
|||
},
|
||||
{
|
||||
path: routes.signup,
|
||||
lazy: () => import('@/pages/RegisterPage')
|
||||
lazy: () => import('@/features/users/pages/RegisterPage')
|
||||
},
|
||||
{
|
||||
path: routes.profile,
|
||||
loader: prefetchProfile,
|
||||
lazy: () => import('@/pages/UserProfilePage')
|
||||
lazy: () => import('@/features/users/pages/UserProfilePage')
|
||||
},
|
||||
{
|
||||
path: routes.restore_password,
|
||||
lazy: () => import('@/pages/RestorePasswordPage')
|
||||
lazy: () => import('@/features/auth/pages/RestorePasswordPage')
|
||||
},
|
||||
{
|
||||
path: routes.password_change,
|
||||
lazy: () => import('@/pages/PasswordChangePage')
|
||||
lazy: () => import('@/features/auth/pages/PasswordChangePage')
|
||||
},
|
||||
{
|
||||
path: routes.library,
|
||||
loader: () => Promise.allSettled([prefetchLibrary(), prefetchUsers()]),
|
||||
lazy: () => import('@/pages/LibraryPage')
|
||||
lazy: () => import('@/features/library/pages/LibraryPage')
|
||||
},
|
||||
{
|
||||
path: routes.create_schema,
|
||||
|
@ -65,24 +65,24 @@ export const Router = createBrowserRouter([
|
|||
{
|
||||
path: `${routes.rsforms}/:id`,
|
||||
loader: data => prefetchRSForm(parseRSFormURL(data.params.id, data.request.url)),
|
||||
lazy: () => import('@/pages/RSFormPage')
|
||||
lazy: () => import('@/features/rsform/pages/RSFormPage')
|
||||
},
|
||||
{
|
||||
path: `${routes.oss}/:id`,
|
||||
loader: data => prefetchOSS(parseOssURL(data.params.id)),
|
||||
lazy: () => import('@/pages/OssPage')
|
||||
lazy: () => import('@/features/oss/pages/OssPage')
|
||||
},
|
||||
{
|
||||
path: routes.manuals,
|
||||
lazy: () => import('@/pages/ManualsPage')
|
||||
lazy: () => import('@/features/help/pages/ManualsPage')
|
||||
},
|
||||
{
|
||||
path: `${routes.icons}`,
|
||||
lazy: () => import('@/pages/IconsPage')
|
||||
lazy: () => import('@/features/home/IconsPage')
|
||||
},
|
||||
{
|
||||
path: `${routes.database_schema}`,
|
||||
lazy: () => import('@/pages/DatabaseSchemaPage')
|
||||
lazy: () => import('@/features/home/DatabaseSchemaPage')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
export { useConceptNavigation } from './Navigation/NavigationContext';
|
||||
export { useBlockNavigation } from './Navigation/NavigationContext';
|
||||
export { urls } from './urls';
|
||||
import { RouterProvider } from 'react-router';
|
||||
|
||||
import { Router } from './Router';
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
/**
|
||||
* Module: generic API for backend REST communications using axios library.
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import { AxiosError, AxiosRequestConfig } from 'axios';
|
||||
import axios, { AxiosError, AxiosRequestConfig } from 'axios';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import { buildConstants } from '@/utils/buildConstants';
|
||||
import { extractErrorMessage } from '@/utils/utils';
|
||||
|
||||
export { AxiosError } from 'axios';
|
||||
export const isAxiosError = axios.isAxiosError;
|
||||
|
||||
const defaultOptions = {
|
||||
xsrfCookieName: 'csrftoken',
|
||||
xsrfHeaderName: 'x-csrftoken',
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import { DataCallback } from '@/backend/apiTransport';
|
||||
|
||||
import { cctextApi, ILexemeResponse } from './api';
|
||||
|
||||
export const useGenerateLexeme = () => {
|
||||
const mutation = useMutation({
|
||||
mutationKey: [cctextApi.baseKey, 'generate-lexeme'],
|
||||
mutationFn: cctextApi.generateLexeme
|
||||
});
|
||||
return {
|
||||
generateLexeme: (
|
||||
data: { text: string }, //
|
||||
onSuccess?: DataCallback<ILexemeResponse>
|
||||
) => mutation.mutate(data, { onSuccess })
|
||||
};
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import { DataCallback } from '@/backend/apiTransport';
|
||||
|
||||
import { cctextApi, ITextResult, IWordFormDTO } from './api';
|
||||
|
||||
export const useInflectText = () => {
|
||||
const mutation = useMutation({
|
||||
mutationKey: [cctextApi.baseKey, 'inflect-text'],
|
||||
mutationFn: cctextApi.inflectText
|
||||
});
|
||||
return {
|
||||
inflectText: (
|
||||
data: IWordFormDTO, //
|
||||
onSuccess?: DataCallback<ITextResult>
|
||||
) => mutation.mutate(data, { onSuccess })
|
||||
};
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import { DataCallback } from '@/backend/apiTransport';
|
||||
|
||||
import { cctextApi, ITextResult } from './api';
|
||||
|
||||
export const useParseText = () => {
|
||||
const mutation = useMutation({
|
||||
mutationKey: [cctextApi.baseKey, 'parse-text'],
|
||||
mutationFn: cctextApi.parseText
|
||||
});
|
||||
return {
|
||||
parseText: (
|
||||
data: { text: string }, //
|
||||
onSuccess?: DataCallback<ITextResult>
|
||||
) => mutation.mutate(data, { onSuccess })
|
||||
};
|
||||
};
|
|
@ -1,29 +0,0 @@
|
|||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { DataCallback } from '@/backend/apiTransport';
|
||||
import { useUpdateTimestamp } from '@/backend/library/useUpdateTimestamp';
|
||||
import { LibraryItemID } from '@/models/library';
|
||||
|
||||
import { IOperationCreateDTO, IOperationDTO, ossApi } from './api';
|
||||
|
||||
export const useOperationCreate = () => {
|
||||
const client = useQueryClient();
|
||||
const { updateTimestamp } = useUpdateTimestamp();
|
||||
const mutation = useMutation({
|
||||
mutationKey: [ossApi.baseKey, 'operation-create'],
|
||||
mutationFn: ossApi.operationCreate,
|
||||
onSuccess: data => {
|
||||
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss);
|
||||
updateTimestamp(data.oss.id);
|
||||
}
|
||||
});
|
||||
return {
|
||||
operationCreate: (
|
||||
data: {
|
||||
itemID: LibraryItemID; //
|
||||
data: IOperationCreateDTO;
|
||||
},
|
||||
onSuccess?: DataCallback<IOperationDTO>
|
||||
) => mutation.mutate(data, { onSuccess: response => onSuccess?.(response.new_operation) })
|
||||
};
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import { useUpdateTimestamp } from '@/backend/library/useUpdateTimestamp';
|
||||
import { LibraryItemID } from '@/models/library';
|
||||
import { IOperationPosition } from '@/models/oss';
|
||||
|
||||
import { ossApi } from './api';
|
||||
|
||||
export const useUpdatePositions = () => {
|
||||
const { updateTimestamp } = useUpdateTimestamp();
|
||||
const mutation = useMutation({
|
||||
mutationKey: [ossApi.baseKey, 'update-positions'],
|
||||
mutationFn: ossApi.updatePositions,
|
||||
onSuccess: (_, variables) => updateTimestamp(variables.itemID)
|
||||
});
|
||||
return {
|
||||
updatePositions: (
|
||||
data: {
|
||||
itemID: LibraryItemID; //
|
||||
positions: IOperationPosition[];
|
||||
isSilent?: boolean;
|
||||
},
|
||||
onSuccess?: () => void
|
||||
) => mutation.mutate(data, { onSuccess })
|
||||
};
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
import { QueryClient } from '@tanstack/react-query';
|
||||
import { AxiosError } from 'axios';
|
||||
|
||||
import { AxiosError } from './apiTransport';
|
||||
import { DELAYS } from './configuration';
|
||||
|
||||
declare module '@tanstack/react-query' {
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import { DataCallback } from '@/backend/apiTransport';
|
||||
import { LibraryItemID } from '@/models/library';
|
||||
import { IExpressionParse } from '@/models/rslang';
|
||||
|
||||
import { ICheckConstituentaDTO, rsformsApi } from './api';
|
||||
|
||||
export const useCheckConstituenta = () => {
|
||||
const mutation = useMutation({
|
||||
mutationKey: [rsformsApi.baseKey, 'check-constituenta'],
|
||||
mutationFn: rsformsApi.checkConstituenta
|
||||
});
|
||||
return {
|
||||
checkConstituenta: (
|
||||
data: {
|
||||
itemID: LibraryItemID; //
|
||||
data: ICheckConstituentaDTO;
|
||||
},
|
||||
onSuccess?: DataCallback<IExpressionParse>
|
||||
) => mutation.mutate(data, { onSuccess }),
|
||||
isPending: mutation.isPending,
|
||||
error: mutation.error
|
||||
};
|
||||
};
|
|
@ -1,38 +0,0 @@
|
|||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { useUpdateTimestamp } from '@/backend/library/useUpdateTimestamp';
|
||||
import { ossApi } from '@/backend/oss/api';
|
||||
import { LibraryItemID } from '@/models/library';
|
||||
|
||||
import { ICstUpdateDTO, rsformsApi } from './api';
|
||||
|
||||
export const useCstUpdate = () => {
|
||||
const client = useQueryClient();
|
||||
const { updateTimestamp } = useUpdateTimestamp();
|
||||
const mutation = useMutation({
|
||||
mutationKey: [rsformsApi.baseKey, 'update-cst'],
|
||||
mutationFn: rsformsApi.cstUpdate,
|
||||
onSuccess: (newCst, variables) => {
|
||||
client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: variables.itemID }).queryKey, prev =>
|
||||
!prev
|
||||
? undefined
|
||||
: {
|
||||
...prev,
|
||||
items: prev.items.map(item => (item.id === newCst.id ? { ...item, ...newCst } : item))
|
||||
}
|
||||
);
|
||||
updateTimestamp(variables.itemID);
|
||||
|
||||
return Promise.allSettled([
|
||||
client.invalidateQueries({ queryKey: [ossApi.baseKey] }),
|
||||
client.invalidateQueries({
|
||||
queryKey: [rsformsApi.baseKey],
|
||||
predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== variables.itemID
|
||||
})
|
||||
]);
|
||||
}
|
||||
});
|
||||
return {
|
||||
cstUpdate: (data: { itemID: LibraryItemID; data: ICstUpdateDTO }) => mutation.mutate(data)
|
||||
};
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { CProps } from '../props';
|
||||
|
||||
export interface DividerProps extends CProps.Styling {
|
||||
interface DividerProps extends CProps.Styling {
|
||||
/** Indicates whether the divider is vertical. */
|
||||
vertical?: boolean;
|
||||
|
||||
|
@ -13,7 +13,7 @@ export interface DividerProps extends CProps.Styling {
|
|||
/**
|
||||
* Horizontal or vertical divider with customizable margins and styling.
|
||||
*/
|
||||
function Divider({ vertical, margins = 'mx-2', className, ...restProps }: DividerProps) {
|
||||
export function Divider({ vertical, margins = 'mx-2', className, ...restProps }: DividerProps) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
|
@ -28,5 +28,3 @@ function Divider({ vertical, margins = 'mx-2', className, ...restProps }: Divide
|
|||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Divider;
|
|
@ -1,17 +1,15 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { CProps } from '../props';
|
||||
|
||||
/**
|
||||
* `flex` column container.
|
||||
* This component is useful for creating vertical layouts with flexbox.
|
||||
*/
|
||||
function FlexColumn({ className, children, ...restProps }: CProps.Div) {
|
||||
export function FlexColumn({ className, children, ...restProps }: CProps.Div) {
|
||||
return (
|
||||
<div className={clsx('cc-column', className)} {...restProps}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FlexColumn;
|
|
@ -1,6 +1,6 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface OverlayProps extends CProps.Styling {
|
||||
/** Id of the overlay. */
|
||||
|
@ -16,7 +16,7 @@ interface OverlayProps extends CProps.Styling {
|
|||
/**
|
||||
* Displays a transparent overlay over the main content.
|
||||
*/
|
||||
function Overlay({
|
||||
export function Overlay({
|
||||
children,
|
||||
className,
|
||||
position = 'top-0 right-0',
|
||||
|
@ -31,5 +31,3 @@ function Overlay({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Overlay;
|
|
@ -20,7 +20,7 @@ interface TooltipProps extends Omit<ITooltip, 'variant'> {
|
|||
/**
|
||||
* Displays content in a tooltip container.
|
||||
*/
|
||||
function Tooltip({
|
||||
export function Tooltip({
|
||||
text,
|
||||
children,
|
||||
layer = 'z-tooltip',
|
||||
|
@ -58,5 +58,3 @@ function Tooltip({
|
|||
document.body
|
||||
);
|
||||
}
|
||||
|
||||
export default Tooltip;
|
4
rsconcept/frontend/src/components/Container/index.tsx
Normal file
4
rsconcept/frontend/src/components/Container/index.tsx
Normal file
|
@ -0,0 +1,4 @@
|
|||
export { Divider } from './Divider';
|
||||
export { FlexColumn } from './FlexColumn';
|
||||
export { Overlay } from './Overlay';
|
||||
export { type PlacesType, Tooltip } from './Tooltip';
|
|
@ -1,8 +1,9 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface ButtonProps extends CProps.Control, CProps.Colors, CProps.Button {
|
||||
/** Icon to display first. */
|
||||
icon?: React.ReactNode;
|
||||
|
@ -20,7 +21,7 @@ interface ButtonProps extends CProps.Control, CProps.Colors, CProps.Button {
|
|||
/**
|
||||
* Customizable `button` with text, icon, tooltips and various styles.
|
||||
*/
|
||||
function Button({
|
||||
export function Button({
|
||||
icon,
|
||||
text,
|
||||
title,
|
||||
|
@ -66,5 +67,3 @@ function Button({
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default Button;
|
|
@ -1,9 +1,13 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface MiniButtonProps extends CProps.Button {
|
||||
/** Button type. */
|
||||
type?: 'button' | 'submit';
|
||||
|
||||
/** Icon to display in the button. */
|
||||
icon: React.ReactNode;
|
||||
|
||||
|
@ -17,7 +21,7 @@ interface MiniButtonProps extends CProps.Button {
|
|||
/**
|
||||
* Displays small transparent button with an icon.
|
||||
*/
|
||||
function MiniButton({
|
||||
export function MiniButton({
|
||||
icon,
|
||||
noHover,
|
||||
noPadding,
|
||||
|
@ -25,12 +29,13 @@ function MiniButton({
|
|||
title,
|
||||
titleHtml,
|
||||
hideTitle,
|
||||
type = 'button',
|
||||
className,
|
||||
...restProps
|
||||
}: MiniButtonProps) {
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
type={type}
|
||||
tabIndex={tabIndex ?? -1}
|
||||
className={clsx(
|
||||
'rounded-lg',
|
||||
|
@ -53,5 +58,3 @@ function MiniButton({
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default MiniButton;
|
|
@ -1,8 +1,9 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface SelectorButtonProps extends CProps.Button {
|
||||
/** Text to display in the button. */
|
||||
text?: string;
|
||||
|
@ -20,7 +21,7 @@ interface SelectorButtonProps extends CProps.Button {
|
|||
/**
|
||||
* Displays a button with an icon and text that opens a dropdown menu.
|
||||
*/
|
||||
function SelectorButton({
|
||||
export function SelectorButton({
|
||||
text,
|
||||
icon,
|
||||
title,
|
||||
|
@ -59,5 +60,3 @@ function SelectorButton({
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectorButton;
|
|
@ -1,6 +1,6 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface SubmitButtonProps extends CProps.Button {
|
||||
/** Text to display in the button. */
|
||||
|
@ -16,7 +16,7 @@ interface SubmitButtonProps extends CProps.Button {
|
|||
/**
|
||||
* Displays submit type button with icon and text.
|
||||
*/
|
||||
function SubmitButton({ text = 'ОК', icon, disabled, loading, className, ...restProps }: SubmitButtonProps) {
|
||||
export function SubmitButton({ text = 'ОК', icon, disabled, loading, className, ...restProps }: SubmitButtonProps) {
|
||||
return (
|
||||
<button
|
||||
type='submit'
|
||||
|
@ -37,5 +37,3 @@ function SubmitButton({ text = 'ОК', icon, disabled, loading, className, ...re
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default SubmitButton;
|
|
@ -20,7 +20,7 @@ interface TextURLProps {
|
|||
/**
|
||||
* Displays a text with a clickable link.
|
||||
*/
|
||||
function TextURL({ text, href, title, color = 'text-sec-600', onClick }: TextURLProps) {
|
||||
export function TextURL({ text, href, title, color = 'text-sec-600', onClick }: TextURLProps) {
|
||||
const design = `cursor-pointer hover:underline ${color}`;
|
||||
if (href) {
|
||||
return (
|
||||
|
@ -39,4 +39,3 @@ function TextURL({ text, href, title, color = 'text-sec-600', onClick }: TextURL
|
|||
}
|
||||
}
|
||||
|
||||
export default TextURL;
|
5
rsconcept/frontend/src/components/Control/index.tsx
Normal file
5
rsconcept/frontend/src/components/Control/index.tsx
Normal file
|
@ -0,0 +1,5 @@
|
|||
export { Button } from './Button';
|
||||
export { MiniButton } from './MiniButton';
|
||||
export { SelectorButton } from './SelectorButton';
|
||||
export { SubmitButton } from './SubmitButton';
|
||||
export { TextURL } from './TextURL';
|
|
@ -17,8 +17,7 @@ import {
|
|||
} from '@tanstack/react-table';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
|
||||
import { CProps } from '../props';
|
||||
import DefaultNoData from './DefaultNoData';
|
||||
import PaginationTools from './PaginationTools';
|
||||
import TableBody from './TableBody';
|
|
@ -5,9 +5,10 @@ import { Table } from '@tanstack/react-table';
|
|||
import clsx from 'clsx';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { IconPageFirst, IconPageLast, IconPageLeft, IconPageRight } from '@/components/Icons';
|
||||
import { prefixes } from '@/utils/constants';
|
||||
|
||||
import { IconPageFirst, IconPageLast, IconPageLeft, IconPageRight } from '../Icons';
|
||||
|
||||
interface PaginationToolsProps<TData> {
|
||||
id?: string;
|
||||
table: Table<TData>;
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { Table } from '@tanstack/react-table';
|
||||
|
||||
import CheckboxTristate from '@/components/ui/CheckboxTristate';
|
||||
import { CheckboxTristate } from '../Input';
|
||||
|
||||
interface SelectAllProps<TData> {
|
||||
table: Table<TData>;
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { Row } from '@tanstack/react-table';
|
||||
|
||||
import Checkbox from '@/components/ui/Checkbox';
|
||||
import { Checkbox } from '../Input';
|
||||
|
||||
interface SelectRowProps<TData> {
|
||||
row: Row<TData>;
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { Column } from '@tanstack/react-table';
|
||||
|
||||
import { IconSortAsc, IconSortDesc } from '@/components/Icons';
|
||||
import { IconSortAsc, IconSortDesc } from '../Icons';
|
||||
|
||||
interface SortingIconProps<TData> {
|
||||
column: Column<TData>;
|
|
@ -3,8 +3,7 @@
|
|||
import { Cell, flexRender, Row, Table } from '@tanstack/react-table';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
|
||||
import { CProps } from '../props';
|
||||
import { IConditionalStyle } from '.';
|
||||
import SelectRow from './SelectRow';
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { AccessPolicy, LibraryItemType, LocationHead } from '@/models/library';
|
||||
import { CstMatchMode, DependencyMode } from '@/models/miscellaneous';
|
||||
import { CstType, ExpressionStatus } from '@/models/rsform';
|
||||
import { AccessPolicy, LibraryItemType, LocationHead } from '@/features/library/models/library';
|
||||
import { CstType, ExpressionStatus } from '@/features/rsform/models/rsform';
|
||||
import { CstMatchMode, DependencyMode } from '@/features/rsform/stores/cstSearch';
|
||||
|
||||
import {
|
||||
IconAlias,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface DropdownProps extends CProps.Styling {
|
||||
/** Indicates whether the dropdown should stretch to the left. */
|
||||
stretchLeft?: boolean;
|
||||
|
@ -17,7 +18,7 @@ interface DropdownProps extends CProps.Styling {
|
|||
/**
|
||||
* Animated list of children with optional positioning and visibility control.
|
||||
*/
|
||||
function Dropdown({
|
||||
export function Dropdown({
|
||||
isOpen,
|
||||
stretchLeft,
|
||||
stretchTop,
|
||||
|
@ -59,5 +60,3 @@ function Dropdown({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Dropdown;
|
|
@ -18,7 +18,7 @@ interface DropdownButtonProps extends CProps.Button {
|
|||
* `button` with optional text, icon, and click functionality styled for use in a {@link Dropdown}.
|
||||
* It supports optional children for custom content or the default text/icon display.
|
||||
*/
|
||||
function DropdownButton({
|
||||
export function DropdownButton({
|
||||
icon,
|
||||
text,
|
||||
className,
|
||||
|
@ -58,5 +58,3 @@ function DropdownButton({
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default DropdownButton;
|
|
@ -1,9 +1,9 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import Checkbox, { CheckboxProps } from './Checkbox';
|
||||
import { Checkbox, CheckboxProps } from '../Input';
|
||||
|
||||
/** Animated {@link Checkbox} inside a {@link Dropdown} item. */
|
||||
function DropdownCheckbox({ onChange: setValue, disabled, ...restProps }: CheckboxProps) {
|
||||
export function DropdownCheckbox({ onChange: setValue, disabled, ...restProps }: CheckboxProps) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
|
@ -17,5 +17,3 @@ function DropdownCheckbox({ onChange: setValue, disabled, ...restProps }: Checkb
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DropdownCheckbox;
|
4
rsconcept/frontend/src/components/Dropdown/index.tsx
Normal file
4
rsconcept/frontend/src/components/Dropdown/index.tsx
Normal file
|
@ -0,0 +1,4 @@
|
|||
export { Dropdown } from './Dropdown';
|
||||
export { DropdownButton } from './DropdownButton';
|
||||
export { DropdownCheckbox } from './DropdownCheckbox';
|
||||
export { useDropdown } from './useDropdown';
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
import useClickedOutside from './useClickedOutside';
|
||||
import useClickedOutside from '@/hooks/useClickedOutside';
|
||||
|
||||
function useDropdown() {
|
||||
export function useDropdown() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const ref = useRef(null);
|
||||
|
||||
|
@ -18,5 +18,3 @@ function useDropdown() {
|
|||
hide: () => setIsOpen(false)
|
||||
};
|
||||
}
|
||||
|
||||
export default useDropdown;
|
|
@ -1,9 +1,10 @@
|
|||
import axios, { type AxiosError } from 'axios';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import PrettyJson from '@/components/ui/PrettyJSON';
|
||||
import { AxiosError, isAxiosError } from '@/backend/apiTransport';
|
||||
import { isResponseHtml } from '@/utils/utils';
|
||||
|
||||
import { PrettyJson } from './View';
|
||||
|
||||
export type ErrorData = string | Error | AxiosError | undefined | null;
|
||||
|
||||
interface InfoErrorProps {
|
||||
|
@ -15,7 +16,7 @@ function DescribeError({ error }: { error: ErrorData }) {
|
|||
return <p>Ошибки отсутствуют</p>;
|
||||
} else if (typeof error === 'string') {
|
||||
return <p>{error}</p>;
|
||||
} else if (!axios.isAxiosError(error)) {
|
||||
} else if (!isAxiosError(error)) {
|
||||
return (
|
||||
<div className='mt-6'>
|
||||
<p>
|
||||
|
@ -76,7 +77,7 @@ function DescribeError({ error }: { error: ErrorData }) {
|
|||
);
|
||||
}
|
||||
|
||||
function InfoError({ error }: InfoErrorProps) {
|
||||
export function InfoError({ error }: InfoErrorProps) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
|
@ -97,5 +98,3 @@ function InfoError({ error }: InfoErrorProps) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default InfoError;
|
|
@ -1,9 +1,10 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CheckboxChecked } from '@/components/Icons';
|
||||
import { CProps } from '@/components/props';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { CheckboxChecked } from '../Icons';
|
||||
import { CProps } from '../props';
|
||||
|
||||
export interface CheckboxProps extends Omit<CProps.Button, 'value' | 'onClick' | 'onChange'> {
|
||||
/** Label to display next to the checkbox. */
|
||||
label?: string;
|
||||
|
@ -21,7 +22,7 @@ export interface CheckboxProps extends Omit<CProps.Button, 'value' | 'onClick' |
|
|||
/**
|
||||
* Component that allows toggling a boolean value.
|
||||
*/
|
||||
function Checkbox({
|
||||
export function Checkbox({
|
||||
disabled,
|
||||
label,
|
||||
title,
|
||||
|
@ -64,7 +65,7 @@ function Checkbox({
|
|||
<div
|
||||
className={clsx(
|
||||
'max-w-[1rem] min-w-[1rem] h-4', //
|
||||
'pt-[0.1rem] pl-[0.1rem]',
|
||||
'pt-[0.05rem] pl-[0.05rem]',
|
||||
'border rounded-sm',
|
||||
'cc-animate-color',
|
||||
{
|
||||
|
@ -79,5 +80,3 @@ function Checkbox({
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default Checkbox;
|
|
@ -1,9 +1,9 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CheckboxChecked, CheckboxNull } from '@/components/Icons';
|
||||
import { CProps } from '@/components/props';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { CheckboxChecked, CheckboxNull } from '../Icons';
|
||||
import { CProps } from '../props';
|
||||
import { CheckboxProps } from './Checkbox';
|
||||
|
||||
export interface CheckboxTristateProps extends Omit<CheckboxProps, 'value' | 'onChange'> {
|
||||
|
@ -17,7 +17,7 @@ export interface CheckboxTristateProps extends Omit<CheckboxProps, 'value' | 'on
|
|||
/**
|
||||
* Component that allows toggling among three states: `true`, `false`, and `null`.
|
||||
*/
|
||||
function CheckboxTristate({
|
||||
export function CheckboxTristate({
|
||||
disabled,
|
||||
label,
|
||||
title,
|
||||
|
@ -66,7 +66,7 @@ function CheckboxTristate({
|
|||
<div
|
||||
className={clsx(
|
||||
'w-4 h-4', //
|
||||
'pt-[0.1rem] pl-[0.1rem]',
|
||||
'pt-[0.05rem] pl-[0.05rem]',
|
||||
'border rounded-sm',
|
||||
'cc-animate-color',
|
||||
{
|
||||
|
@ -82,5 +82,3 @@ function CheckboxTristate({
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default CheckboxTristate;
|
|
@ -10,7 +10,7 @@ interface ErrorFieldProps extends CProps.Styling {
|
|||
/**
|
||||
* Displays an error message for input field.
|
||||
*/
|
||||
function ErrorField({ error, className, ...restProps }: ErrorFieldProps): React.ReactElement | null {
|
||||
export function ErrorField({ error, className, ...restProps }: ErrorFieldProps): React.ReactElement | null {
|
||||
if (!error) {
|
||||
return null;
|
||||
}
|
||||
|
@ -20,5 +20,3 @@ function ErrorField({ error, className, ...restProps }: ErrorFieldProps): React.
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ErrorField;
|
|
@ -3,11 +3,10 @@
|
|||
import clsx from 'clsx';
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
import { IconUpload } from '@/components/Icons';
|
||||
import { CProps } from '@/components/props';
|
||||
|
||||
import Button from './Button';
|
||||
import Label from './Label';
|
||||
import { Button } from '../Control';
|
||||
import { IconUpload } from '../Icons';
|
||||
import { CProps } from '../props';
|
||||
import { Label } from './Label';
|
||||
|
||||
interface FileInputProps extends Omit<CProps.Input, 'accept' | 'type'> {
|
||||
/** Label to display in file upload button. */
|
||||
|
@ -23,7 +22,7 @@ interface FileInputProps extends Omit<CProps.Input, 'accept' | 'type'> {
|
|||
/**
|
||||
* FileInput is a component for selecting a `file`, displaying the selected file name.
|
||||
*/
|
||||
function FileInput({ id, label, acceptType, title, className, style, onChange, ...restProps }: FileInputProps) {
|
||||
export function FileInput({ id, label, acceptType, title, className, style, onChange, ...restProps }: FileInputProps) {
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
const [fileName, setFileName] = useState('');
|
||||
|
||||
|
@ -56,5 +55,3 @@ function FileInput({ id, label, acceptType, title, className, style, onChange, .
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FileInput;
|
|
@ -1,6 +1,6 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface LabelProps extends CProps.Label {
|
||||
/** Text to display. */
|
||||
|
@ -12,7 +12,7 @@ interface LabelProps extends CProps.Label {
|
|||
*
|
||||
* Note: Html label component is used only if `htmlFor` prop is set.
|
||||
*/
|
||||
function Label({ text, className, ...restProps }: LabelProps) {
|
||||
export function Label({ text, className, ...restProps }: LabelProps) {
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
|
@ -30,5 +30,3 @@ function Label({ text, className, ...restProps }: LabelProps) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Label;
|
|
@ -9,9 +9,10 @@ import Select, {
|
|||
StylesConfig
|
||||
} from 'react-select';
|
||||
|
||||
import { IconClose, IconDropArrow, IconDropArrowUp } from '@/components/Icons';
|
||||
import useWindowSize from '@/hooks/useWindowSize';
|
||||
import { APP_COLORS, SELECT_THEME } from '@/styling/color';
|
||||
import { APP_COLORS, SELECT_THEME } from '@/styling/colors';
|
||||
|
||||
import { IconClose, IconDropArrow, IconDropArrowUp } from '../Icons';
|
||||
|
||||
function DropdownIndicator<Option, Group extends GroupBase<Option> = GroupBase<Option>>(
|
||||
props: DropdownIndicatorProps<Option, true, Group>
|
||||
|
@ -45,7 +46,7 @@ export interface SelectMultiProps<Option, Group extends GroupBase<Option> = Grou
|
|||
/**
|
||||
* Displays a multi-select component.
|
||||
*/
|
||||
function SelectMulti<Option, Group extends GroupBase<Option> = GroupBase<Option>>({
|
||||
export function SelectMulti<Option, Group extends GroupBase<Option> = GroupBase<Option>>({
|
||||
noPortal,
|
||||
...restProps
|
||||
}: SelectMultiProps<Option, Group>) {
|
||||
|
@ -125,5 +126,3 @@ function SelectMulti<Option, Group extends GroupBase<Option> = GroupBase<Option>
|
|||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectMulti;
|
|
@ -9,9 +9,10 @@ import Select, {
|
|||
StylesConfig
|
||||
} from 'react-select';
|
||||
|
||||
import { IconClose, IconDropArrow, IconDropArrowUp } from '@/components/Icons';
|
||||
import useWindowSize from '@/hooks/useWindowSize';
|
||||
import { APP_COLORS, SELECT_THEME } from '@/styling/color';
|
||||
import { APP_COLORS, SELECT_THEME } from '@/styling/colors';
|
||||
|
||||
import { IconClose, IconDropArrow, IconDropArrowUp } from '../Icons';
|
||||
|
||||
function DropdownIndicator<Option, Group extends GroupBase<Option> = GroupBase<Option>>(
|
||||
props: DropdownIndicatorProps<Option, false, Group>
|
||||
|
@ -46,7 +47,7 @@ export interface SelectSingleProps<Option, Group extends GroupBase<Option> = Gro
|
|||
/**
|
||||
* Displays a single-select component.
|
||||
*/
|
||||
function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option>>({
|
||||
export function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option>>({
|
||||
noPortal,
|
||||
noBorder,
|
||||
...restProps
|
||||
|
@ -123,5 +124,3 @@ function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option
|
|||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectSingle;
|
|
@ -1,12 +1,12 @@
|
|||
import clsx from 'clsx';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { IconDropArrow, IconPageRight } from '@/components/Icons';
|
||||
import { CProps } from '@/components/props';
|
||||
import { globals, PARAMETER } from '@/utils/constants';
|
||||
|
||||
import MiniButton from './MiniButton';
|
||||
import Overlay from './Overlay';
|
||||
import { Overlay } from '../Container';
|
||||
import { MiniButton } from '../Control';
|
||||
import { IconDropArrow, IconPageRight } from '../Icons';
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface SelectTreeProps<ItemType> extends CProps.Styling {
|
||||
/** Current value. */
|
||||
|
@ -34,7 +34,7 @@ interface SelectTreeProps<ItemType> extends CProps.Styling {
|
|||
/**
|
||||
* Displays a tree of items and allows user to select one.
|
||||
*/
|
||||
function SelectTree<ItemType>({
|
||||
export function SelectTree<ItemType>({
|
||||
items,
|
||||
value,
|
||||
getParent,
|
||||
|
@ -123,5 +123,3 @@ function SelectTree<ItemType>({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectTree;
|
|
@ -1,9 +1,8 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
|
||||
import ErrorField from './ErrorField';
|
||||
import Label from './Label';
|
||||
import { Label } from '../Input/Label';
|
||||
import { CProps } from '../props';
|
||||
import { ErrorField } from './ErrorField';
|
||||
|
||||
export interface TextAreaProps extends CProps.Editor, CProps.ErrorProcessing, CProps.Colors, CProps.TextArea {
|
||||
/** Indicates that padding should be minimal. */
|
||||
|
@ -19,7 +18,7 @@ export interface TextAreaProps extends CProps.Editor, CProps.ErrorProcessing, CP
|
|||
/**
|
||||
* Displays a customizable textarea with a label.
|
||||
*/
|
||||
function TextArea({
|
||||
export function TextArea({
|
||||
id,
|
||||
label,
|
||||
required,
|
||||
|
@ -57,7 +56,7 @@ function TextArea({
|
|||
'resize-none': noResize,
|
||||
'border': !noBorder,
|
||||
'flex-grow max-w-full': dense,
|
||||
'mt-2': !dense,
|
||||
'mt-2': !dense && !!label,
|
||||
'clr-outline': !noOutline
|
||||
},
|
||||
colors,
|
||||
|
@ -71,5 +70,3 @@ function TextArea({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextArea;
|
|
@ -1,9 +1,8 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
|
||||
import ErrorField from './ErrorField';
|
||||
import Label from './Label';
|
||||
import { Label } from '../Input/Label';
|
||||
import { CProps } from '../props';
|
||||
import { ErrorField } from './ErrorField';
|
||||
|
||||
interface TextInputProps extends CProps.Editor, CProps.ErrorProcessing, CProps.Colors, CProps.Input {
|
||||
/** Indicates that padding should be minimal. */
|
||||
|
@ -22,7 +21,7 @@ function preventEnterCapture(event: React.KeyboardEvent<HTMLInputElement>) {
|
|||
/**
|
||||
* Displays a customizable input with a label.
|
||||
*/
|
||||
function TextInput({
|
||||
export function TextInput({
|
||||
id,
|
||||
label,
|
||||
dense,
|
||||
|
@ -55,7 +54,7 @@ function TextInput({
|
|||
{
|
||||
'px-3': !noBorder || !disabled,
|
||||
'flex-grow max-w-full': dense,
|
||||
'mt-2': !dense,
|
||||
'mt-2': !dense && !!label,
|
||||
'border': !noBorder,
|
||||
'clr-outline': !noOutline
|
||||
},
|
||||
|
@ -70,5 +69,3 @@ function TextInput({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextInput;
|
10
rsconcept/frontend/src/components/Input/index.tsx
Normal file
10
rsconcept/frontend/src/components/Input/index.tsx
Normal file
|
@ -0,0 +1,10 @@
|
|||
export { Checkbox, type CheckboxProps } from './Checkbox';
|
||||
export { CheckboxTristate } from './CheckboxTristate';
|
||||
export { ErrorField } from './ErrorField';
|
||||
export { FileInput } from './FileInput';
|
||||
export { Label } from './Label';
|
||||
export { SelectMulti, type SelectMultiProps } from './SelectMulti';
|
||||
export { SelectSingle, type SelectSingleProps } from './SelectSingle';
|
||||
export { SelectTree } from './SelectTree';
|
||||
export { TextArea } from './TextArea';
|
||||
export { TextInput } from './TextInput';
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import { APP_COLORS } from '@/styling/color';
|
||||
import { APP_COLORS } from '@/styling/colors';
|
||||
|
||||
interface LoaderProps {
|
||||
/** Scale of the loader from 1 to 10. */
|
||||
|
@ -54,7 +54,7 @@ const animatePulse = (startBig: boolean, duration: string) => {
|
|||
/**
|
||||
* Displays animated loader.
|
||||
*/
|
||||
function Loader({ scale = 5, circular }: LoaderProps) {
|
||||
export function Loader({ scale = 5, circular }: LoaderProps) {
|
||||
if (circular) {
|
||||
return (
|
||||
<div className='flex justify-center' aria-label='three-circles-loading' aria-busy='true' role='progressbar'>
|
||||
|
@ -89,5 +89,3 @@ function Loader({ scale = 5, circular }: LoaderProps) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Loader;
|
19
rsconcept/frontend/src/components/Modal/ModalBackdrop.tsx
Normal file
19
rsconcept/frontend/src/components/Modal/ModalBackdrop.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
|
||||
interface ModalBackdropProps {
|
||||
onHide: () => void;
|
||||
}
|
||||
|
||||
export function ModalBackdrop({ onHide }: ModalBackdropProps) {
|
||||
return (
|
||||
<>
|
||||
<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')}
|
||||
onClick={onHide}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -2,46 +2,25 @@
|
|||
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { IconClose } from '@/components/Icons';
|
||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||
import { CProps } from '@/components/props';
|
||||
import { HelpTopic } from '@/features/help/models/helpTopic';
|
||||
import useEscapeKey from '@/hooks/useEscapeKey';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { prepareTooltip } from '@/utils/labels';
|
||||
import { prepareTooltip } from '@/utils/utils';
|
||||
|
||||
import Button from './Button';
|
||||
import MiniButton from './MiniButton';
|
||||
import { Button, MiniButton, SubmitButton } from '../Control';
|
||||
import { IconClose } from '../Icons';
|
||||
import { CProps } from '../props';
|
||||
import { BadgeHelp } from '../shared/BadgeHelp';
|
||||
import { ModalBackdrop } from './ModalBackdrop';
|
||||
|
||||
export interface ModalProps extends CProps.Styling {
|
||||
/** Title of the modal window. */
|
||||
header?: string;
|
||||
|
||||
/** Text of the submit button. */
|
||||
submitText?: string;
|
||||
|
||||
/** Tooltip for the submit button when the form is invalid. */
|
||||
submitInvalidTooltip?: string;
|
||||
|
||||
/** Indicates that form is readonly. */
|
||||
readonly?: boolean;
|
||||
|
||||
/** Indicates that submit button is enabled. */
|
||||
canSubmit?: boolean;
|
||||
|
||||
/** Indicates that the modal window should be scrollable. */
|
||||
overflowVisible?: boolean;
|
||||
|
||||
/** Callback to be called before submit. */
|
||||
beforeSubmit?: () => boolean;
|
||||
|
||||
/** Callback to be called after submit. */
|
||||
onSubmit?: () => void;
|
||||
|
||||
/** Callback to be called after cancel. */
|
||||
onCancel?: () => void;
|
||||
|
||||
/** Help topic to be displayed in the modal window. */
|
||||
helpTopic?: HelpTopic;
|
||||
|
||||
|
@ -49,58 +28,64 @@ export interface ModalProps extends CProps.Styling {
|
|||
hideHelpWhen?: () => boolean;
|
||||
}
|
||||
|
||||
interface ModalFormProps extends ModalProps {
|
||||
/** Text of the submit button. */
|
||||
submitText?: string;
|
||||
|
||||
/** Tooltip for the submit button when the form is invalid. */
|
||||
submitInvalidTooltip?: string;
|
||||
|
||||
/** Indicates that submit button is enabled. */
|
||||
canSubmit?: boolean;
|
||||
|
||||
/** Callback to be called before submit. */
|
||||
beforeSubmit?: () => boolean;
|
||||
|
||||
/** Callback to be called after submit. */
|
||||
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a customizable modal window.
|
||||
* Displays a customizable modal window with submit form.
|
||||
*/
|
||||
function Modal({
|
||||
export function ModalForm({
|
||||
children,
|
||||
|
||||
className,
|
||||
header,
|
||||
submitText = 'Продолжить',
|
||||
submitInvalidTooltip,
|
||||
|
||||
readonly,
|
||||
canSubmit,
|
||||
overflowVisible,
|
||||
|
||||
canSubmit = true,
|
||||
submitText = 'Продолжить',
|
||||
submitInvalidTooltip,
|
||||
beforeSubmit,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
className,
|
||||
|
||||
helpTopic,
|
||||
hideHelpWhen,
|
||||
...restProps
|
||||
}: React.PropsWithChildren<ModalProps>) {
|
||||
}: React.PropsWithChildren<ModalFormProps>) {
|
||||
const hideDialog = useDialogsStore(state => state.hideDialog);
|
||||
useEscapeKey(hideDialog);
|
||||
|
||||
const handleCancel = () => {
|
||||
hideDialog();
|
||||
onCancel?.();
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
if (beforeSubmit && !beforeSubmit()) {
|
||||
return;
|
||||
}
|
||||
onSubmit?.();
|
||||
onSubmit(event);
|
||||
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')}
|
||||
onClick={hideDialog}
|
||||
/>
|
||||
<div
|
||||
<ModalBackdrop onHide={hideDialog} />
|
||||
<form
|
||||
className={clsx(
|
||||
'cc-animate-modal',
|
||||
'z-modal absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-1/2',
|
||||
'border rounded-xl bg-prim-100'
|
||||
)}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{helpTopic && !hideHelpWhen?.() ? (
|
||||
<div className='float-left mt-2 ml-2'>
|
||||
|
@ -113,7 +98,7 @@ function Modal({
|
|||
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
|
||||
icon={<IconClose size='1.25rem' />}
|
||||
className='float-right mt-2 mr-2'
|
||||
onClick={handleCancel}
|
||||
onClick={hideDialog}
|
||||
/>
|
||||
|
||||
{header ? <h1 className='px-12 py-2 select-none'>{header}</h1> : null}
|
||||
|
@ -133,22 +118,16 @@ function Modal({
|
|||
</div>
|
||||
|
||||
<div className='z-modalControls my-2 flex gap-12 justify-center text-sm'>
|
||||
{!readonly ? (
|
||||
<Button
|
||||
autoFocus
|
||||
text={submitText}
|
||||
title={!canSubmit ? submitInvalidTooltip : ''}
|
||||
className='min-w-[7rem]'
|
||||
colors='clr-btn-primary'
|
||||
disabled={!canSubmit}
|
||||
onClick={handleSubmit}
|
||||
/>
|
||||
) : null}
|
||||
<Button text={readonly ? 'Закрыть' : 'Отмена'} className='min-w-[7rem]' onClick={handleCancel} />
|
||||
<SubmitButton
|
||||
autoFocus
|
||||
text={submitText}
|
||||
title={!canSubmit ? submitInvalidTooltip : ''}
|
||||
className='min-w-[7rem]'
|
||||
disabled={!canSubmit}
|
||||
/>
|
||||
<Button text='Отмена' className='min-w-[7rem]' onClick={hideDialog} />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Modal;
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
import clsx from 'clsx';
|
||||
|
||||
import Loader from './Loader';
|
||||
import { Loader } from '@/components/Loader';
|
||||
|
||||
function ModalLoader() {
|
||||
export function ModalLoader() {
|
||||
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')} />
|
||||
|
@ -21,5 +21,3 @@ function ModalLoader() {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModalLoader;
|
79
rsconcept/frontend/src/components/Modal/ModalView.tsx
Normal file
79
rsconcept/frontend/src/components/Modal/ModalView.tsx
Normal file
|
@ -0,0 +1,79 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
|
||||
import useEscapeKey from '@/hooks/useEscapeKey';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { prepareTooltip } from '@/utils/utils';
|
||||
|
||||
import { Button, MiniButton } from '../Control';
|
||||
import { IconClose } from '../Icons';
|
||||
import { BadgeHelp } from '../shared/BadgeHelp';
|
||||
import { ModalBackdrop } from './ModalBackdrop';
|
||||
import { ModalProps } from './ModalForm';
|
||||
|
||||
interface ModalViewProps extends ModalProps {}
|
||||
|
||||
/**
|
||||
* Displays a customizable modal window with submit form.
|
||||
*/
|
||||
export function ModalView({
|
||||
children,
|
||||
className,
|
||||
header,
|
||||
overflowVisible,
|
||||
helpTopic,
|
||||
hideHelpWhen,
|
||||
...restProps
|
||||
}: React.PropsWithChildren<ModalViewProps>) {
|
||||
const hideDialog = useDialogsStore(state => state.hideDialog);
|
||||
useEscapeKey(hideDialog);
|
||||
|
||||
return (
|
||||
<div className='fixed top-0 left-0 w-full h-full z-modal cursor-default'>
|
||||
<ModalBackdrop onHide={hideDialog} />
|
||||
<div
|
||||
className={clsx(
|
||||
'cc-animate-modal',
|
||||
'z-modal absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-1/2',
|
||||
'border rounded-xl bg-prim-100'
|
||||
)}
|
||||
>
|
||||
{helpTopic && !hideHelpWhen?.() ? (
|
||||
<div className='float-left mt-2 ml-2'>
|
||||
<BadgeHelp topic={helpTopic} className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')} padding='p-0' />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<MiniButton
|
||||
noPadding
|
||||
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
|
||||
icon={<IconClose size='1.25rem' />}
|
||||
className='float-right mt-2 mr-2'
|
||||
onClick={hideDialog}
|
||||
/>
|
||||
|
||||
{header ? <h1 className='px-12 py-2 select-none'>{header}</h1> : null}
|
||||
|
||||
<div
|
||||
className={clsx(
|
||||
'overscroll-contain max-h-[calc(100svh-8rem)] max-w-[100svw] xs:max-w-[calc(100svw-2rem)] outline-none',
|
||||
{
|
||||
'overflow-auto': !overflowVisible,
|
||||
'overflow-visible': overflowVisible
|
||||
},
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<div className='z-modalControls my-2 flex gap-12 justify-center text-sm'>
|
||||
<Button text='Закрыть' className='min-w-[7rem]' onClick={hideDialog} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
3
rsconcept/frontend/src/components/Modal/index.tsx
Normal file
3
rsconcept/frontend/src/components/Modal/index.tsx
Normal file
|
@ -0,0 +1,3 @@
|
|||
export { ModalForm } from './ModalForm';
|
||||
export { ModalLoader } from './ModalLoader';
|
||||
export { ModalView } from './ModalView';
|
|
@ -1,26 +0,0 @@
|
|||
import { Extension } from '@codemirror/state';
|
||||
import { hoverTooltip } from '@codemirror/view';
|
||||
|
||||
import { IRSForm } from '@/models/rsform';
|
||||
import { findAliasAt } from '@/utils/codemirror';
|
||||
import { domTooltipConstituenta } from '@/utils/codemirror';
|
||||
|
||||
const tooltipProducer = (schema: IRSForm, canClick?: boolean) => {
|
||||
return hoverTooltip((view, pos) => {
|
||||
const { alias, start, end } = findAliasAt(pos, view.state);
|
||||
if (!alias) {
|
||||
return null;
|
||||
}
|
||||
const cst = schema.cstByAlias.get(alias);
|
||||
return {
|
||||
pos: start,
|
||||
end: end,
|
||||
above: false,
|
||||
create: () => domTooltipConstituenta(cst, canClick)
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export function rsHoverTooltip(schema: IRSForm, canClick?: boolean): Extension {
|
||||
return [tooltipProducer(schema, canClick)];
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
import { syntaxTree } from '@codemirror/language';
|
||||
import { Extension } from '@codemirror/state';
|
||||
import { hoverTooltip } from '@codemirror/view';
|
||||
|
||||
import { IEntityReference, ISyntacticReference } from '@/models/language';
|
||||
import { IRSForm } from '@/models/rsform';
|
||||
import {
|
||||
domTooltipEntityReference,
|
||||
domTooltipSyntacticReference,
|
||||
findContainedNodes,
|
||||
findReferenceAt
|
||||
} from '@/utils/codemirror';
|
||||
|
||||
import { RefEntity } from './parse/parser.terms';
|
||||
|
||||
export const tooltipProducer = (schema: IRSForm, canClick?: boolean) => {
|
||||
return hoverTooltip((view, pos) => {
|
||||
const parse = findReferenceAt(pos, view.state);
|
||||
if (!parse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ('entity' in parse.ref) {
|
||||
const cst = schema.cstByAlias.get(parse.ref.entity);
|
||||
return {
|
||||
pos: parse.start,
|
||||
end: parse.end,
|
||||
above: false,
|
||||
create: () => domTooltipEntityReference(parse.ref as IEntityReference, cst, canClick)
|
||||
};
|
||||
} else {
|
||||
let masterText: string | undefined = undefined;
|
||||
if (parse.ref.offset > 0) {
|
||||
const entities = findContainedNodes(parse.end, view.state.doc.length, syntaxTree(view.state), [RefEntity]);
|
||||
if (parse.ref.offset <= entities.length) {
|
||||
const master = entities[parse.ref.offset - 1];
|
||||
masterText = view.state.doc.sliceString(master.from, master.to);
|
||||
}
|
||||
} else {
|
||||
const entities = findContainedNodes(0, parse.start, syntaxTree(view.state), [RefEntity]);
|
||||
if (-parse.ref.offset <= entities.length) {
|
||||
const master = entities[-parse.ref.offset - 1];
|
||||
masterText = view.state.doc.sliceString(master.from, master.to);
|
||||
}
|
||||
}
|
||||
return {
|
||||
pos: parse.start,
|
||||
end: parse.end,
|
||||
above: false,
|
||||
create: () => domTooltipSyntacticReference(parse.ref as ISyntacticReference, masterText, canClick)
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export function refsHoverTooltip(schema: IRSForm, canClick?: boolean): Extension {
|
||||
return [tooltipProducer(schema, canClick)];
|
||||
}
|
|
@ -2,9 +2,10 @@ import clsx from 'clsx';
|
|||
import type { TabProps as TabPropsImpl } from 'react-tabs';
|
||||
import { Tab as TabImpl } from 'react-tabs';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface TabLabelProps extends Omit<TabPropsImpl, 'children'>, CProps.Titled {
|
||||
/** Label to display in the tab. */
|
||||
label?: string;
|
||||
|
@ -13,7 +14,7 @@ interface TabLabelProps extends Omit<TabPropsImpl, 'children'>, CProps.Titled {
|
|||
/**
|
||||
* Displays a tab header with a label.
|
||||
*/
|
||||
function TabLabel({ label, title, titleHtml, hideTitle, className, ...otherProps }: TabLabelProps) {
|
||||
export function TabLabel({ label, title, titleHtml, hideTitle, className, ...otherProps }: TabLabelProps) {
|
||||
return (
|
||||
<TabImpl
|
||||
className={clsx(
|
||||
|
@ -38,5 +39,3 @@ function TabLabel({ label, title, titleHtml, hideTitle, className, ...otherProps
|
|||
}
|
||||
|
||||
TabLabel.tabsRole = 'Tab';
|
||||
|
||||
export default TabLabel;
|
2
rsconcept/frontend/src/components/Tabs/index.tsx
Normal file
2
rsconcept/frontend/src/components/Tabs/index.tsx
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { TabLabel } from './TabLabel';
|
||||
export { TabList, TabPanel, Tabs } from 'react-tabs';
|
|
@ -12,7 +12,7 @@ interface EmbedYoutubeProps {
|
|||
/**
|
||||
* Embeds a YouTube video into the page using the given video ID and dimensions.
|
||||
*/
|
||||
function EmbedYoutube({ videoID, pxHeight, pxWidth }: EmbedYoutubeProps) {
|
||||
export function EmbedYoutube({ videoID, pxHeight, pxWidth }: EmbedYoutubeProps) {
|
||||
if (!pxWidth) {
|
||||
pxWidth = (pxHeight * 16) / 9;
|
||||
}
|
||||
|
@ -41,5 +41,3 @@ function EmbedYoutube({ videoID, pxHeight, pxWidth }: EmbedYoutubeProps) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EmbedYoutube;
|
|
@ -14,7 +14,7 @@ interface IndicatorProps extends CProps.Titled, CProps.Styling {
|
|||
/**
|
||||
* Displays a status `icon` with a tooltip.
|
||||
*/
|
||||
function Indicator({ icon, title, titleHtml, hideTitle, noPadding, className, ...restProps }: IndicatorProps) {
|
||||
export function Indicator({ icon, title, titleHtml, hideTitle, noPadding, className, ...restProps }: IndicatorProps) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
|
@ -35,5 +35,3 @@ function Indicator({ icon, title, titleHtml, hideTitle, noPadding, className, ..
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Indicator;
|
|
@ -5,12 +5,10 @@ import { CProps } from '@/components/props';
|
|||
/**
|
||||
* Wraps content in a div with a centered text.
|
||||
*/
|
||||
function NoData({ className, children, ...restProps }: CProps.Div) {
|
||||
export function NoData({ className, children, ...restProps }: CProps.Div) {
|
||||
return (
|
||||
<div className={clsx('p-3 flex flex-col items-center text-center select-none w-full', className)} {...restProps}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default NoData;
|
|
@ -23,7 +23,7 @@ interface PDFViewerProps {
|
|||
/**
|
||||
* Displays a PDF file using an embedded viewer.
|
||||
*/
|
||||
function PDFViewer({ file, offsetXpx, minWidth = MINIMUM_WIDTH }: PDFViewerProps) {
|
||||
export function PDFViewer({ file, offsetXpx, minWidth = MINIMUM_WIDTH }: PDFViewerProps) {
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
const pageWidth = Math.max(minWidth, Math.min((windowSize?.width ?? 0) - (offsetXpx ?? 0) - 10, MAXIMUM_WIDTH));
|
||||
|
@ -31,5 +31,3 @@ function PDFViewer({ file, offsetXpx, minWidth = MINIMUM_WIDTH }: PDFViewerProps
|
|||
|
||||
return <embed src={`${file}#toolbar=0`} className='p-3' style={{ width: pageWidth, height: pageHeight }} />;
|
||||
}
|
||||
|
||||
export default PDFViewer;
|
|
@ -5,9 +5,7 @@ interface PrettyJsonProps {
|
|||
/**
|
||||
* Displays JSON data in a formatted string.
|
||||
*/
|
||||
function PrettyJson({ data }: PrettyJsonProps) {
|
||||
export function PrettyJson({ data }: PrettyJsonProps) {
|
||||
const text = JSON.stringify(data, null, 2);
|
||||
return <pre>{text === '{}' ? '' : text}</pre>;
|
||||
}
|
||||
|
||||
export default PrettyJson;
|
|
@ -18,7 +18,7 @@ export interface TextContentProps extends CProps.Styling {
|
|||
/**
|
||||
* Displays text limited to a certain number of symbols.
|
||||
*/
|
||||
function TextContent({ className, text, maxLength, noTooltip, ...restProps }: TextContentProps) {
|
||||
export function TextContent({ className, text, maxLength, noTooltip, ...restProps }: TextContentProps) {
|
||||
const truncated = maxLength ? truncateToLastWord(text, maxLength) : text;
|
||||
const isTruncated = maxLength && text.length > maxLength;
|
||||
return (
|
||||
|
@ -32,5 +32,3 @@ function TextContent({ className, text, maxLength, noTooltip, ...restProps }: Te
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextContent;
|
|
@ -3,7 +3,7 @@ import clsx from 'clsx';
|
|||
import { CProps } from '@/components/props';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import MiniButton from './MiniButton';
|
||||
import { MiniButton } from '../Control';
|
||||
|
||||
interface ValueIconProps extends CProps.Styling, CProps.Titled {
|
||||
/** Id of the component. */
|
||||
|
@ -34,7 +34,7 @@ interface ValueIconProps extends CProps.Styling, CProps.Titled {
|
|||
/**
|
||||
* Displays a value with an icon that can be clicked.
|
||||
*/
|
||||
function ValueIcon({
|
||||
export function ValueIcon({
|
||||
id,
|
||||
dense,
|
||||
icon,
|
||||
|
@ -73,5 +73,3 @@ function ValueIcon({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ValueIcon;
|
|
@ -19,7 +19,7 @@ interface ValueLabeledProps extends CProps.Styling {
|
|||
/**
|
||||
* Displays a labeled value.
|
||||
*/
|
||||
function ValueLabeled({ id, label, text, title, className, ...restProps }: ValueLabeledProps) {
|
||||
export function ValueLabeled({ id, label, text, title, className, ...restProps }: ValueLabeledProps) {
|
||||
return (
|
||||
<div className={clsx('flex justify-between gap-6', className)} {...restProps}>
|
||||
<span title={title}>{label}</span>
|
||||
|
@ -27,5 +27,3 @@ function ValueLabeled({ id, label, text, title, className, ...restProps }: Value
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ValueLabeled;
|
|
@ -1,7 +1,7 @@
|
|||
import { CProps } from '@/components/props';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
|
||||
import ValueIcon from './ValueIcon';
|
||||
import { ValueIcon } from './ValueIcon';
|
||||
|
||||
interface ValueStatsProps extends CProps.Styling, CProps.Titled {
|
||||
/** Id of the component. */
|
||||
|
@ -17,8 +17,6 @@ interface ValueStatsProps extends CProps.Styling, CProps.Titled {
|
|||
/**
|
||||
* Displays statistics value with an icon.
|
||||
*/
|
||||
function ValueStats(props: ValueStatsProps) {
|
||||
export function ValueStats(props: ValueStatsProps) {
|
||||
return <ValueIcon dense smallThreshold={PARAMETER.statSmallThreshold} textClassName='min-w-[1.4rem]' {...props} />;
|
||||
}
|
||||
|
||||
export default ValueStats;
|
9
rsconcept/frontend/src/components/View/index.tsx
Normal file
9
rsconcept/frontend/src/components/View/index.tsx
Normal file
|
@ -0,0 +1,9 @@
|
|||
export { EmbedYoutube } from './EmbedYoutube';
|
||||
export { Indicator } from './Indicator';
|
||||
export { NoData } from './NoData';
|
||||
export { PDFViewer } from './PDFViewer';
|
||||
export { PrettyJson } from './PrettyJSON';
|
||||
export { TextContent } from './TextContent';
|
||||
export { ValueIcon } from './ValueIcon';
|
||||
export { ValueLabeled } from './ValueLabeled';
|
||||
export { ValueStats } from './ValueStats';
|
|
@ -1,37 +0,0 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import SelectMulti, { SelectMultiProps } from '@/components/ui/SelectMulti';
|
||||
import { Grammeme } from '@/models/language';
|
||||
import { getCompatibleGrams } from '@/models/languageAPI';
|
||||
import { compareGrammemeOptions, IGrammemeOption, SelectorGrammemes } from '@/utils/selectors';
|
||||
|
||||
interface SelectMultiGrammemeProps
|
||||
extends Omit<SelectMultiProps<IGrammemeOption>, 'value' | 'onChange'>,
|
||||
CProps.Styling {
|
||||
value: IGrammemeOption[];
|
||||
onChange: (newValue: IGrammemeOption[]) => void;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
function SelectMultiGrammeme({ value, onChange, ...restProps }: SelectMultiGrammemeProps) {
|
||||
const [options, setOptions] = useState<IGrammemeOption[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const compatible = getCompatibleGrams(
|
||||
value.filter(data => Object.values(Grammeme).includes(data.value as Grammeme)).map(data => data.value as Grammeme)
|
||||
);
|
||||
setOptions(SelectorGrammemes.filter(({ value }) => compatible.includes(value as Grammeme)));
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<SelectMulti
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={newValue => onChange([...newValue].sort(compareGrammemeOptions))}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectMultiGrammeme;
|
|
@ -1,37 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { CProps } from '@/components/props';
|
||||
import WordformButton from '@/dialogs/DlgEditReference/WordformButton';
|
||||
import { Grammeme } from '@/models/language';
|
||||
import { prefixes } from '@/utils/constants';
|
||||
import { DefaultWordForms, IGrammemeOption, SelectorGrammemes } from '@/utils/selectors';
|
||||
|
||||
interface SelectWordFormProps extends CProps.Styling {
|
||||
value: IGrammemeOption[];
|
||||
onChange: React.Dispatch<React.SetStateAction<IGrammemeOption[]>>;
|
||||
}
|
||||
|
||||
function SelectWordForm({ value, onChange, className, ...restProps }: SelectWordFormProps) {
|
||||
function handleSelect(grams: Grammeme[]) {
|
||||
onChange(SelectorGrammemes.filter(({ value }) => grams.includes(value as Grammeme)));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={clsx('text-xs sm:text-sm', className)} {...restProps}>
|
||||
{DefaultWordForms.slice(0, 12).map((data, index) => (
|
||||
<WordformButton
|
||||
key={`${prefixes.wordform_list}${index}`}
|
||||
text={data.text}
|
||||
example={data.example}
|
||||
grams={data.grams}
|
||||
isSelected={data.grams.every(gram => value.find(item => (item.value as Grammeme) === gram))}
|
||||
onSelectGrams={handleSelect}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectWordForm;
|
|
@ -1,14 +1,14 @@
|
|||
import React, { Suspense } from 'react';
|
||||
|
||||
import { PlacesType, Tooltip } from '@/components/Container';
|
||||
import { TextURL } from '@/components/Control';
|
||||
import { IconHelp } from '@/components/Icons';
|
||||
import { Loader } from '@/components/Loader';
|
||||
import { CProps } from '@/components/props';
|
||||
import Loader from '@/components/ui/Loader';
|
||||
import TextURL from '@/components/ui/TextURL';
|
||||
import Tooltip, { PlacesType } from '@/components/ui/Tooltip';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { HelpTopic } from '@/features/help/models/helpTopic';
|
||||
import { usePreferencesStore } from '@/stores/preferences';
|
||||
|
||||
const TopicPage = React.lazy(() => import('@/pages/ManualsPage/TopicPage'));
|
||||
const TopicPage = React.lazy(() => import('@/features/help/pages/ManualsPage/TopicPage'));
|
||||
|
||||
interface BadgeHelpProps extends CProps.Styling {
|
||||
/** Topic to display in a tooltip. */
|
||||
|
@ -27,7 +27,7 @@ interface BadgeHelpProps extends CProps.Styling {
|
|||
/**
|
||||
* Display help icon with a manual page tooltip.
|
||||
*/
|
||||
function BadgeHelp({ topic, padding = 'p-1', ...restProps }: BadgeHelpProps) {
|
||||
export function BadgeHelp({ topic, padding = 'p-1', ...restProps }: BadgeHelpProps) {
|
||||
const showHelp = usePreferencesStore(state => state.showHelp);
|
||||
|
||||
if (!showHelp) {
|
||||
|
@ -49,5 +49,3 @@ function BadgeHelp({ topic, padding = 'p-1', ...restProps }: BadgeHelpProps) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BadgeHelp;
|
|
@ -1,11 +1,10 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { Overlay } from '@/components/Container';
|
||||
import { IconSearch } from '@/components/Icons';
|
||||
import { TextInput } from '@/components/Input';
|
||||
import { CProps } from '@/components/props';
|
||||
|
||||
import Overlay from './Overlay';
|
||||
import TextInput from './TextInput';
|
||||
|
||||
interface SearchBarProps extends CProps.Styling {
|
||||
/** Id of the search bar. */
|
||||
id?: string;
|
||||
|
@ -29,7 +28,7 @@ interface SearchBarProps extends CProps.Styling {
|
|||
/**
|
||||
* Displays a search bar with a search icon and text input.
|
||||
*/
|
||||
function SearchBar({
|
||||
export function SearchBar({
|
||||
id,
|
||||
query,
|
||||
noIcon,
|
||||
|
@ -58,5 +57,3 @@ function SearchBar({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SearchBar;
|
|
@ -1 +0,0 @@
|
|||
export { default } from './PDFViewer';
|
|
@ -1,72 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useLibrary } from '@/backend/library/useLibrary';
|
||||
import { IconReset } from '@/components/Icons';
|
||||
import PickSchema from '@/components/select/PickSchema';
|
||||
import Label from '@/components/ui/Label';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import Modal from '@/components/ui/Modal';
|
||||
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library';
|
||||
import { IOperation, IOperationSchema, OperationID } from '@/models/oss';
|
||||
import { sortItemsForOSS } from '@/models/ossAPI';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
export interface DlgChangeInputSchemaProps {
|
||||
oss: IOperationSchema;
|
||||
target: IOperation;
|
||||
onSubmit: (target: OperationID, newSchema: LibraryItemID | undefined) => void;
|
||||
}
|
||||
|
||||
function DlgChangeInputSchema() {
|
||||
const { oss, target, onSubmit } = useDialogsStore(state => state.props as DlgChangeInputSchemaProps);
|
||||
const [selected, setSelected] = useState<LibraryItemID | undefined>(target.result ?? undefined);
|
||||
const { items } = useLibrary();
|
||||
const sortedItems = sortItemsForOSS(oss, items);
|
||||
const isValid = target.result !== selected;
|
||||
|
||||
function baseFilter(item: ILibraryItem) {
|
||||
return !oss.schemas.includes(item.id) || item.id === selected || item.id === target.result;
|
||||
}
|
||||
|
||||
function handleSelectLocation(newValue: LibraryItemID) {
|
||||
setSelected(newValue);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
overflowVisible
|
||||
header='Выбор концептуальной схемы'
|
||||
submitText='Подтвердить выбор'
|
||||
canSubmit={isValid}
|
||||
onSubmit={() => onSubmit(target.id, selected)}
|
||||
className={clsx('w-[35rem]', 'pb-3 px-6 cc-column')}
|
||||
>
|
||||
<div className='flex justify-between gap-3 items-center'>
|
||||
<div className='flex gap-3'>
|
||||
<Label text='Загружаемая концептуальная схема' />
|
||||
<MiniButton
|
||||
title='Сбросить выбор схемы'
|
||||
noHover
|
||||
noPadding
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => setSelected(undefined)}
|
||||
disabled={selected == undefined}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<PickSchema
|
||||
items={sortedItems}
|
||||
itemType={LibraryItemType.RSFORM}
|
||||
value={selected} // prettier: split-line
|
||||
onChange={handleSelectLocation}
|
||||
rows={14}
|
||||
baseFilter={baseFilter}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgChangeInputSchema;
|
|
@ -1,60 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useAuthSuspense } from '@/backend/auth/useAuth';
|
||||
import SelectLocationContext from '@/components/select/SelectLocationContext';
|
||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||
import Label from '@/components/ui/Label';
|
||||
import Modal from '@/components/ui/Modal';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import { LocationHead } from '@/models/library';
|
||||
import { combineLocation, validateLocation } from '@/models/libraryAPI';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
import { limits } from '@/utils/constants';
|
||||
|
||||
export interface DlgChangeLocationProps {
|
||||
initial: string;
|
||||
onChangeLocation: (newLocation: string) => void;
|
||||
}
|
||||
|
||||
function DlgChangeLocation() {
|
||||
const { initial, onChangeLocation } = useDialogsStore(state => state.props as DlgChangeLocationProps);
|
||||
const { user } = useAuthSuspense();
|
||||
const [head, setHead] = useState<LocationHead>(initial.substring(0, 2) as LocationHead);
|
||||
const [body, setBody] = useState<string>(initial.substring(3));
|
||||
|
||||
const location = combineLocation(head, body);
|
||||
const isValid = initial !== location && validateLocation(location);
|
||||
|
||||
function handleSelectLocation(newValue: string) {
|
||||
setHead(newValue.substring(0, 2) as LocationHead);
|
||||
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
overflowVisible
|
||||
header='Изменение расположения'
|
||||
submitText='Переместить'
|
||||
submitInvalidTooltip={`Допустимы буквы, цифры, подчерк, пробел и "!". Сегмент пути не может начинаться и заканчиваться пробелом. Общая длина (с корнем) не должна превышать ${limits.location_len}`}
|
||||
canSubmit={isValid}
|
||||
onSubmit={() => onChangeLocation(location)}
|
||||
className={clsx('w-[35rem]', 'pb-3 px-6 flex gap-3 h-[9rem]')}
|
||||
>
|
||||
<div className='flex flex-col gap-2 min-w-[7rem] h-min'>
|
||||
<Label className='select-none' text='Корень' />
|
||||
<SelectLocationHead
|
||||
value={head} // prettier: split-lines
|
||||
onChange={setHead}
|
||||
excluded={!user.is_staff ? [LocationHead.LIBRARY] : []}
|
||||
/>
|
||||
</div>
|
||||
<SelectLocationContext value={location} onChange={handleSelectLocation} className='max-h-[9.2rem]' />
|
||||
<TextArea id='dlg_cst_body' label='Путь' rows={3} value={body} onChange={event => setBody(event.target.value)} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgChangeLocation;
|
|
@ -1,146 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useConceptNavigation } from '@/app/Navigation/NavigationContext';
|
||||
import { urls } from '@/app/urls';
|
||||
import { useAuthSuspense } from '@/backend/auth/useAuth';
|
||||
import { IRCloneLibraryItemDTO } from '@/backend/library/api';
|
||||
import { useCloneItem } from '@/backend/library/useCloneItem';
|
||||
import { VisibilityIcon } from '@/components/DomainIcons';
|
||||
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
||||
import SelectLocationContext from '@/components/select/SelectLocationContext';
|
||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||
import Checkbox from '@/components/ui/Checkbox';
|
||||
import Label from '@/components/ui/Label';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import Modal from '@/components/ui/Modal';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import { AccessPolicy, ILibraryItem, LocationHead } from '@/models/library';
|
||||
import { cloneTitle, combineLocation, validateLocation } from '@/models/libraryAPI';
|
||||
import { ConstituentaID } from '@/models/rsform';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
export interface DlgCloneLibraryItemProps {
|
||||
base: ILibraryItem;
|
||||
initialLocation: string;
|
||||
selected: ConstituentaID[];
|
||||
totalCount: number;
|
||||
}
|
||||
|
||||
function DlgCloneLibraryItem() {
|
||||
const { base, initialLocation, selected, totalCount } = useDialogsStore(
|
||||
state => state.props as DlgCloneLibraryItemProps
|
||||
);
|
||||
const router = useConceptNavigation();
|
||||
const { user } = useAuthSuspense();
|
||||
|
||||
const [title, setTitle] = useState(cloneTitle(base));
|
||||
const [alias, setAlias] = useState(base.alias);
|
||||
const [comment, setComment] = useState(base.comment);
|
||||
const [visible, setVisible] = useState(true);
|
||||
const [policy, setPolicy] = useState(AccessPolicy.PUBLIC);
|
||||
|
||||
const [onlySelected, setOnlySelected] = useState(false);
|
||||
|
||||
const [head, setHead] = useState(initialLocation.substring(0, 2) as LocationHead);
|
||||
const [body, setBody] = useState(initialLocation.substring(3));
|
||||
const location = combineLocation(head, body);
|
||||
|
||||
const { cloneItem } = useCloneItem();
|
||||
|
||||
const canSubmit = title !== '' && alias !== '' && validateLocation(location);
|
||||
|
||||
function handleSelectLocation(newValue: string) {
|
||||
setHead(newValue.substring(0, 2) as LocationHead);
|
||||
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
const data: IRCloneLibraryItemDTO = {
|
||||
id: base.id,
|
||||
item_type: base.item_type,
|
||||
title: title,
|
||||
alias: alias,
|
||||
comment: comment,
|
||||
read_only: false,
|
||||
visible: visible,
|
||||
access_policy: policy,
|
||||
location: location
|
||||
};
|
||||
if (onlySelected) {
|
||||
data.items = selected;
|
||||
}
|
||||
cloneItem(data, newSchema => router.push(urls.schema(newSchema.id)));
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
header='Создание копии концептуальной схемы'
|
||||
canSubmit={canSubmit}
|
||||
submitText='Создать'
|
||||
onSubmit={handleSubmit}
|
||||
className={clsx('px-6 py-2', 'cc-column', 'max-h-full w-[30rem]')}
|
||||
>
|
||||
<TextInput
|
||||
id='dlg_full_name'
|
||||
label='Полное название'
|
||||
value={title}
|
||||
onChange={event => setTitle(event.target.value)}
|
||||
/>
|
||||
<div className='flex justify-between gap-3'>
|
||||
<TextInput
|
||||
id='dlg_alias'
|
||||
label='Сокращение'
|
||||
value={alias}
|
||||
className='w-[15rem]'
|
||||
onChange={event => setAlias(event.target.value)}
|
||||
/>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<Label text='Доступ' className='self-center select-none' />
|
||||
<div className='ml-auto cc-icons'>
|
||||
<SelectAccessPolicy
|
||||
stretchLeft // prettier: split-lines
|
||||
value={policy}
|
||||
onChange={newPolicy => setPolicy(newPolicy)}
|
||||
/>
|
||||
|
||||
<MiniButton
|
||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||
icon={<VisibilityIcon value={visible} />}
|
||||
onClick={() => setVisible(prev => !prev)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-between gap-3'>
|
||||
<div className='flex flex-col gap-2 w-[7rem] h-min'>
|
||||
<Label text='Корень' />
|
||||
<SelectLocationHead value={head} onChange={setHead} excluded={!user.is_staff ? [LocationHead.LIBRARY] : []} />
|
||||
</div>
|
||||
<SelectLocationContext value={location} onChange={handleSelectLocation} />
|
||||
<TextArea
|
||||
id='dlg_cst_body'
|
||||
label='Путь'
|
||||
rows={3}
|
||||
value={body}
|
||||
onChange={event => setBody(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TextArea id='dlg_comment' label='Описание' value={comment} onChange={event => setComment(event.target.value)} />
|
||||
|
||||
<Checkbox
|
||||
id='dlg_only_selected'
|
||||
label={`Только выбранные конституенты [${selected.length} из ${totalCount}]`}
|
||||
value={onlySelected}
|
||||
onChange={value => setOnlySelected(value)}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgCloneLibraryItem;
|
|
@ -1,161 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
|
||||
import { useLibrary } from '@/backend/library/useLibrary';
|
||||
import { IOperationCreateDTO } from '@/backend/oss/api';
|
||||
import Modal from '@/components/ui/Modal';
|
||||
import TabLabel from '@/components/ui/TabLabel';
|
||||
import { LibraryItemID } from '@/models/library';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { IOperationSchema, OperationID, OperationType } from '@/models/oss';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
import { describeOperationType, labelOperationType } from '@/utils/labels';
|
||||
|
||||
import TabInputOperation from './TabInputOperation';
|
||||
import TabSynthesisOperation from './TabSynthesisOperation';
|
||||
|
||||
export interface DlgCreateOperationProps {
|
||||
oss: IOperationSchema;
|
||||
onCreate: (data: IOperationCreateDTO) => void;
|
||||
initialInputs: OperationID[];
|
||||
}
|
||||
|
||||
export enum TabID {
|
||||
INPUT = 0,
|
||||
SYNTHESIS = 1
|
||||
}
|
||||
|
||||
function DlgCreateOperation() {
|
||||
const { items: libraryItems } = useLibrary();
|
||||
|
||||
const { oss, onCreate, initialInputs } = useDialogsStore(state => state.props as DlgCreateOperationProps);
|
||||
const [activeTab, setActiveTab] = useState(initialInputs.length > 0 ? TabID.SYNTHESIS : TabID.INPUT);
|
||||
|
||||
const [alias, setAlias] = useState('');
|
||||
const [title, setTitle] = useState('');
|
||||
const [comment, setComment] = useState('');
|
||||
const [inputs, setInputs] = useState<OperationID[]>(initialInputs);
|
||||
const [attachedID, setAttachedID] = useState<LibraryItemID | undefined>(undefined);
|
||||
const [createSchema, setCreateSchema] = useState(false);
|
||||
|
||||
const isValid = (() => {
|
||||
if (alias === '') {
|
||||
return false;
|
||||
}
|
||||
if (activeTab === TabID.SYNTHESIS && inputs.length === 0) {
|
||||
return false;
|
||||
}
|
||||
if (activeTab === TabID.INPUT && !attachedID) {
|
||||
if (oss.items.some(operation => operation.alias === alias)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
|
||||
useEffect(() => {
|
||||
if (attachedID) {
|
||||
const schema = libraryItems.find(value => value.id === attachedID);
|
||||
if (schema) {
|
||||
setAlias(schema.alias);
|
||||
setTitle(schema.title);
|
||||
setComment(schema.comment);
|
||||
}
|
||||
}
|
||||
}, [attachedID, libraryItems]);
|
||||
|
||||
const handleSubmit = () => {
|
||||
onCreate({
|
||||
item_data: {
|
||||
position_x: 0,
|
||||
position_y: 0,
|
||||
alias: alias,
|
||||
title: title,
|
||||
comment: comment,
|
||||
operation_type: activeTab === TabID.INPUT ? OperationType.INPUT : OperationType.SYNTHESIS,
|
||||
result: activeTab === TabID.INPUT ? attachedID ?? null : null
|
||||
},
|
||||
positions: [],
|
||||
arguments: activeTab === TabID.INPUT ? undefined : inputs.length > 0 ? inputs : undefined,
|
||||
create_schema: createSchema
|
||||
});
|
||||
};
|
||||
|
||||
function handleSelectTab(newTab: TabID, last: TabID) {
|
||||
if (last === newTab) {
|
||||
return;
|
||||
}
|
||||
if (newTab === TabID.INPUT) {
|
||||
setAttachedID(undefined);
|
||||
} else {
|
||||
setInputs(initialInputs);
|
||||
}
|
||||
setActiveTab(newTab);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
header='Создание операции'
|
||||
submitText='Создать'
|
||||
canSubmit={isValid}
|
||||
onSubmit={handleSubmit}
|
||||
className='w-[40rem] px-6 h-[32rem]'
|
||||
helpTopic={HelpTopic.CC_OSS}
|
||||
>
|
||||
<Tabs
|
||||
selectedTabClassName='clr-selected'
|
||||
className='flex flex-col pt-2'
|
||||
selectedIndex={activeTab}
|
||||
onSelect={handleSelectTab}
|
||||
>
|
||||
<TabList
|
||||
className={clsx('self-center absolute top-[2.4rem]', 'flex', 'border divide-x rounded-none', 'bg-prim-200')}
|
||||
>
|
||||
<TabLabel
|
||||
title={describeOperationType(OperationType.INPUT)}
|
||||
label={labelOperationType(OperationType.INPUT)}
|
||||
/>
|
||||
<TabLabel
|
||||
title={describeOperationType(OperationType.SYNTHESIS)}
|
||||
label={labelOperationType(OperationType.SYNTHESIS)}
|
||||
/>
|
||||
</TabList>
|
||||
|
||||
<TabPanel>
|
||||
<TabInputOperation
|
||||
oss={oss}
|
||||
alias={alias}
|
||||
onChangeAlias={setAlias}
|
||||
comment={comment}
|
||||
onChangeComment={setComment}
|
||||
title={title}
|
||||
onChangeTitle={setTitle}
|
||||
attachedID={attachedID}
|
||||
onChangeAttachedID={setAttachedID}
|
||||
createSchema={createSchema}
|
||||
onChangeCreateSchema={setCreateSchema}
|
||||
/>
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel>
|
||||
<TabSynthesisOperation
|
||||
oss={oss}
|
||||
alias={alias}
|
||||
onChangeAlias={setAlias}
|
||||
comment={comment}
|
||||
onChangeComment={setComment}
|
||||
title={title}
|
||||
onChangeTitle={setTitle}
|
||||
inputs={inputs}
|
||||
setInputs={setInputs}
|
||||
/>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgCreateOperation;
|
|
@ -1,120 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useLibrary } from '@/backend/library/useLibrary';
|
||||
import { IconReset } from '@/components/Icons';
|
||||
import PickSchema from '@/components/select/PickSchema';
|
||||
import Checkbox from '@/components/ui/Checkbox';
|
||||
import Label from '@/components/ui/Label';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library';
|
||||
import { IOperationSchema } from '@/models/oss';
|
||||
import { sortItemsForOSS } from '@/models/ossAPI';
|
||||
|
||||
interface TabInputOperationProps {
|
||||
oss: IOperationSchema;
|
||||
alias: string;
|
||||
onChangeAlias: (newValue: string) => void;
|
||||
title: string;
|
||||
onChangeTitle: (newValue: string) => void;
|
||||
comment: string;
|
||||
onChangeComment: (newValue: string) => void;
|
||||
attachedID: LibraryItemID | undefined;
|
||||
onChangeAttachedID: (newValue: LibraryItemID | undefined) => void;
|
||||
createSchema: boolean;
|
||||
onChangeCreateSchema: (newValue: boolean) => void;
|
||||
}
|
||||
|
||||
function TabInputOperation({
|
||||
oss,
|
||||
alias,
|
||||
onChangeAlias,
|
||||
title,
|
||||
onChangeTitle,
|
||||
comment,
|
||||
onChangeComment,
|
||||
attachedID,
|
||||
onChangeAttachedID,
|
||||
createSchema,
|
||||
onChangeCreateSchema
|
||||
}: TabInputOperationProps) {
|
||||
const { items: libraryItems } = useLibrary();
|
||||
const sortedItems = sortItemsForOSS(oss, libraryItems);
|
||||
|
||||
function baseFilter(item: ILibraryItem) {
|
||||
return !oss.schemas.includes(item.id);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (createSchema) {
|
||||
onChangeAttachedID(undefined);
|
||||
}
|
||||
}, [createSchema, onChangeAttachedID]);
|
||||
|
||||
return (
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<TextInput
|
||||
id='operation_title'
|
||||
label='Полное название'
|
||||
value={title}
|
||||
onChange={event => onChangeTitle(event.target.value)}
|
||||
disabled={attachedID !== undefined}
|
||||
/>
|
||||
<div className='flex gap-6'>
|
||||
<TextInput
|
||||
id='operation_alias'
|
||||
label='Сокращение'
|
||||
className='w-[16rem]'
|
||||
value={alias}
|
||||
onChange={event => onChangeAlias(event.target.value)}
|
||||
disabled={attachedID !== undefined}
|
||||
/>
|
||||
|
||||
<TextArea
|
||||
id='operation_comment'
|
||||
label='Описание'
|
||||
noResize
|
||||
rows={3}
|
||||
value={comment}
|
||||
onChange={event => onChangeComment(event.target.value)}
|
||||
disabled={attachedID !== undefined}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-between gap-3 items-center'>
|
||||
<div className='flex gap-3'>
|
||||
<Label text='Загружаемая концептуальная схема' />
|
||||
<MiniButton
|
||||
title='Сбросить выбор схемы'
|
||||
noHover
|
||||
noPadding
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => onChangeAttachedID(undefined)}
|
||||
disabled={attachedID == undefined}
|
||||
/>
|
||||
</div>
|
||||
<Checkbox
|
||||
value={createSchema}
|
||||
onChange={onChangeCreateSchema}
|
||||
label='Создать новую схему'
|
||||
titleHtml='Создать пустую схему для загрузки'
|
||||
/>
|
||||
</div>
|
||||
{!createSchema ? (
|
||||
<PickSchema
|
||||
items={sortedItems}
|
||||
value={attachedID}
|
||||
itemType={LibraryItemType.RSFORM}
|
||||
onChange={onChangeAttachedID}
|
||||
rows={8}
|
||||
baseFilter={baseFilter}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TabInputOperation;
|
|
@ -1,66 +0,0 @@
|
|||
import PickMultiOperation from '@/components/select/PickMultiOperation';
|
||||
import FlexColumn from '@/components/ui/FlexColumn';
|
||||
import Label from '@/components/ui/Label';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import { IOperationSchema, OperationID } from '@/models/oss';
|
||||
|
||||
interface TabSynthesisOperationProps {
|
||||
oss: IOperationSchema;
|
||||
alias: string;
|
||||
onChangeAlias: (newValue: string) => void;
|
||||
title: string;
|
||||
onChangeTitle: (newValue: string) => void;
|
||||
comment: string;
|
||||
onChangeComment: (newValue: string) => void;
|
||||
inputs: OperationID[];
|
||||
setInputs: React.Dispatch<React.SetStateAction<OperationID[]>>;
|
||||
}
|
||||
|
||||
function TabSynthesisOperation({
|
||||
oss,
|
||||
alias,
|
||||
onChangeAlias,
|
||||
title,
|
||||
onChangeTitle,
|
||||
comment,
|
||||
onChangeComment,
|
||||
inputs,
|
||||
setInputs
|
||||
}: TabSynthesisOperationProps) {
|
||||
return (
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<TextInput
|
||||
id='operation_title'
|
||||
label='Полное название'
|
||||
value={title}
|
||||
onChange={event => onChangeTitle(event.target.value)}
|
||||
/>
|
||||
<div className='flex gap-6'>
|
||||
<TextInput
|
||||
id='operation_alias'
|
||||
label='Сокращение'
|
||||
className='w-[16rem]'
|
||||
value={alias}
|
||||
onChange={event => onChangeAlias(event.target.value)}
|
||||
/>
|
||||
|
||||
<TextArea
|
||||
id='operation_comment'
|
||||
label='Описание'
|
||||
noResize
|
||||
rows={3}
|
||||
value={comment}
|
||||
onChange={event => onChangeComment(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FlexColumn>
|
||||
<Label text={`Выбор аргументов: [ ${inputs.length} ]`} />
|
||||
<PickMultiOperation items={oss.items} value={inputs} onChange={setInputs} rows={6} />
|
||||
</FlexColumn>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TabSynthesisOperation;
|
|
@ -1,73 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { IVersionCreateDTO } from '@/backend/library/api';
|
||||
import Checkbox from '@/components/ui/Checkbox';
|
||||
import Modal from '@/components/ui/Modal';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import { IVersionInfo } from '@/models/library';
|
||||
import { nextVersion } from '@/models/libraryAPI';
|
||||
import { ConstituentaID } from '@/models/rsform';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
export interface DlgCreateVersionProps {
|
||||
versions: IVersionInfo[];
|
||||
onCreate: (data: IVersionCreateDTO) => void;
|
||||
selected: ConstituentaID[];
|
||||
totalCount: number;
|
||||
}
|
||||
|
||||
function DlgCreateVersion() {
|
||||
const { versions, selected, totalCount, onCreate } = useDialogsStore(state => state.props as DlgCreateVersionProps);
|
||||
const [version, setVersion] = useState(versions.length > 0 ? nextVersion(versions[0].version) : '1.0.0');
|
||||
const [description, setDescription] = useState('');
|
||||
const [onlySelected, setOnlySelected] = useState(false);
|
||||
|
||||
const canSubmit = !versions.find(ver => ver.version === version);
|
||||
|
||||
function handleSubmit() {
|
||||
onCreate({
|
||||
version: version,
|
||||
description: description,
|
||||
items: onlySelected ? selected : undefined
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
header='Создание версии'
|
||||
canSubmit={canSubmit}
|
||||
onSubmit={handleSubmit}
|
||||
submitText='Создать'
|
||||
className={clsx('cc-column', 'w-[30rem]', 'py-2 px-6')}
|
||||
>
|
||||
<TextInput
|
||||
id='dlg_version'
|
||||
dense
|
||||
label='Версия'
|
||||
className='w-[16rem]'
|
||||
value={version}
|
||||
onChange={event => setVersion(event.target.value)}
|
||||
/>
|
||||
<TextArea
|
||||
id='dlg_description'
|
||||
spellCheck
|
||||
label='Описание'
|
||||
rows={3}
|
||||
value={description}
|
||||
onChange={event => setDescription(event.target.value)}
|
||||
/>
|
||||
<Checkbox
|
||||
id='dlg_only_selected'
|
||||
label={`Только выбранные конституенты [${selected.length} из ${totalCount}]`}
|
||||
value={onlySelected}
|
||||
onChange={value => setOnlySelected(value)}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgCreateVersion;
|
|
@ -1,60 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
|
||||
import Checkbox from '@/components/ui/Checkbox';
|
||||
import Modal from '@/components/ui/Modal';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { IOperation, OperationID } from '@/models/oss';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
export interface DlgDeleteOperationProps {
|
||||
target: IOperation;
|
||||
onSubmit: (targetID: OperationID, keepConstituents: boolean, deleteSchema: boolean) => void;
|
||||
}
|
||||
|
||||
function DlgDeleteOperation() {
|
||||
const { target, onSubmit } = useDialogsStore(state => state.props as DlgDeleteOperationProps);
|
||||
const [keepConstituents, setKeepConstituents] = useState(false);
|
||||
const [deleteSchema, setDeleteSchema] = useState(false);
|
||||
|
||||
function handleSubmit() {
|
||||
onSubmit(target.id, keepConstituents, deleteSchema);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
overflowVisible
|
||||
header='Удаление операции'
|
||||
submitText='Подтвердить удаление'
|
||||
canSubmit={true}
|
||||
onSubmit={handleSubmit}
|
||||
className={clsx('w-[35rem]', 'pb-3 px-6 cc-column', 'select-none')}
|
||||
helpTopic={HelpTopic.CC_PROPAGATION}
|
||||
>
|
||||
<TextInput disabled dense noBorder id='operation_alias' label='Операция' value={target.alias} />
|
||||
<Checkbox
|
||||
label='Сохранить наследованные конституенты'
|
||||
titleHtml='Наследованные конституенты <br/>превратятся в дописанные'
|
||||
value={keepConstituents}
|
||||
onChange={setKeepConstituents}
|
||||
disabled={target.result === null}
|
||||
/>
|
||||
<Checkbox
|
||||
label='Удалить схему'
|
||||
titleHtml={
|
||||
!target.is_owned || target.result === undefined
|
||||
? 'Привязанную схему нельзя удалить'
|
||||
: 'Удалить схему вместе с операцией'
|
||||
}
|
||||
value={deleteSchema}
|
||||
onChange={setDeleteSchema}
|
||||
disabled={!target.is_owned || target.result === null}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgDeleteOperation;
|
|
@ -1,192 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
|
||||
import { IOperationUpdateDTO } from '@/backend/oss/api';
|
||||
import { useRSForms } from '@/backend/rsform/useRSForms';
|
||||
import Modal from '@/components/ui/Modal';
|
||||
import TabLabel from '@/components/ui/TabLabel';
|
||||
import { LibraryItemID } from '@/models/library';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { ICstSubstitute, IOperation, IOperationSchema, OperationID, OperationType } from '@/models/oss';
|
||||
import { SubstitutionValidator } from '@/models/ossAPI';
|
||||
import { ConstituentaID } from '@/models/rsform';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
import TabArguments from './TabArguments';
|
||||
import TabOperation from './TabOperation';
|
||||
import TabSynthesis from './TabSynthesis';
|
||||
|
||||
export interface DlgEditOperationProps {
|
||||
oss: IOperationSchema;
|
||||
target: IOperation;
|
||||
onSubmit: (data: IOperationUpdateDTO) => void;
|
||||
}
|
||||
|
||||
export enum TabID {
|
||||
CARD = 0,
|
||||
ARGUMENTS = 1,
|
||||
SUBSTITUTION = 2
|
||||
}
|
||||
|
||||
function DlgEditOperation() {
|
||||
const { oss, target, onSubmit } = useDialogsStore(state => state.props as DlgEditOperationProps);
|
||||
const [activeTab, setActiveTab] = useState(TabID.CARD);
|
||||
|
||||
const [alias, setAlias] = useState(target.alias);
|
||||
const [title, setTitle] = useState(target.title);
|
||||
const [comment, setComment] = useState(target.comment);
|
||||
|
||||
const [isCorrect, setIsCorrect] = useState(true);
|
||||
const [validationText, setValidationText] = useState('');
|
||||
|
||||
const initialInputs = oss.graph.expandInputs([target.id]);
|
||||
const [inputs, setInputs] = useState<OperationID[]>(initialInputs);
|
||||
const inputOperations = inputs.map(id => oss.operationByID.get(id)!);
|
||||
|
||||
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>(target.substitutions);
|
||||
const [suggestions, setSuggestions] = useState<ICstSubstitute[]>([]);
|
||||
|
||||
const [schemasIDs, setSchemaIDs] = useState<LibraryItemID[]>([]);
|
||||
const schemas = useRSForms(schemasIDs);
|
||||
|
||||
const isModified =
|
||||
alias !== target.alias ||
|
||||
title !== target.title ||
|
||||
comment !== target.comment ||
|
||||
JSON.stringify(initialInputs) !== JSON.stringify(inputs) ||
|
||||
JSON.stringify(substitutions) !== JSON.stringify(target.substitutions);
|
||||
|
||||
const canSubmit = isModified && alias !== '';
|
||||
|
||||
const getSchemaByCst = useCallback(
|
||||
(id: ConstituentaID) => {
|
||||
for (const schema of schemas) {
|
||||
const cst = schema.items.find(cst => cst.id === id);
|
||||
if (cst) {
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
[schemas]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setSchemaIDs(inputOperations.map(operation => operation.result).filter(id => id !== null));
|
||||
}, [inputOperations]);
|
||||
|
||||
useEffect(() => {
|
||||
if (schemas.length !== schemasIDs.length || schemas.length === 0) {
|
||||
return;
|
||||
}
|
||||
setSubstitutions(prev =>
|
||||
prev.filter(sub => {
|
||||
const original = getSchemaByCst(sub.original);
|
||||
if (!original || !schemasIDs.includes(original.id)) {
|
||||
return false;
|
||||
}
|
||||
const substitution = getSchemaByCst(sub.substitution);
|
||||
if (!substitution || !schemasIDs.includes(substitution.id)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
);
|
||||
}, [schemasIDs, schemas, getSchemaByCst]);
|
||||
|
||||
useEffect(() => {
|
||||
if (schemas.length !== schemasIDs.length || schemas.length === 0) {
|
||||
return;
|
||||
}
|
||||
const validator = new SubstitutionValidator(schemas, substitutions);
|
||||
setIsCorrect(validator.validate());
|
||||
setValidationText(validator.msg);
|
||||
setSuggestions(validator.suggestions);
|
||||
}, [substitutions, schemas, schemasIDs.length]);
|
||||
|
||||
function handleSubmit() {
|
||||
onSubmit({
|
||||
target: target.id,
|
||||
item_data: {
|
||||
alias: alias,
|
||||
title: title,
|
||||
comment: comment
|
||||
},
|
||||
positions: [],
|
||||
arguments: target.operation_type !== OperationType.SYNTHESIS ? undefined : inputs,
|
||||
substitutions: target.operation_type !== OperationType.SYNTHESIS ? undefined : substitutions
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
header='Редактирование операции'
|
||||
submitText='Сохранить'
|
||||
canSubmit={canSubmit}
|
||||
onSubmit={handleSubmit}
|
||||
className='w-[40rem] px-6 h-[32rem]'
|
||||
helpTopic={HelpTopic.UI_SUBSTITUTIONS}
|
||||
hideHelpWhen={() => activeTab !== TabID.SUBSTITUTION}
|
||||
>
|
||||
<Tabs
|
||||
selectedTabClassName='clr-selected'
|
||||
className='flex flex-col'
|
||||
selectedIndex={activeTab}
|
||||
onSelect={setActiveTab}
|
||||
>
|
||||
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none', 'bg-prim-200')}>
|
||||
<TabLabel title='Текстовые поля' label='Карточка' className='w-[8rem]' />
|
||||
{target.operation_type === OperationType.SYNTHESIS ? (
|
||||
<TabLabel title='Выбор аргументов операции' label='Аргументы' className='w-[8rem]' />
|
||||
) : null}
|
||||
{target.operation_type === OperationType.SYNTHESIS ? (
|
||||
<TabLabel
|
||||
titleHtml={'Таблица отождествлений' + (isCorrect ? '' : '<br/>(не прошла проверку)')}
|
||||
label={isCorrect ? 'Отождествления' : 'Отождествления*'}
|
||||
className='w-[8rem]'
|
||||
/>
|
||||
) : null}
|
||||
</TabList>
|
||||
|
||||
<TabPanel>
|
||||
<TabOperation
|
||||
alias={alias}
|
||||
onChangeAlias={setAlias}
|
||||
comment={comment}
|
||||
onChangeComment={setComment}
|
||||
title={title}
|
||||
onChangeTitle={setTitle}
|
||||
/>
|
||||
</TabPanel>
|
||||
|
||||
{target.operation_type === OperationType.SYNTHESIS ? (
|
||||
<TabPanel>
|
||||
<TabArguments
|
||||
target={target.id} // prettier: split-lines
|
||||
oss={oss}
|
||||
inputs={inputs}
|
||||
setInputs={setInputs}
|
||||
/>
|
||||
</TabPanel>
|
||||
) : null}
|
||||
{target.operation_type === OperationType.SYNTHESIS ? (
|
||||
<TabPanel>
|
||||
<TabSynthesis
|
||||
schemas={schemas}
|
||||
validationText={validationText}
|
||||
isCorrect={isCorrect}
|
||||
substitutions={substitutions}
|
||||
setSubstitutions={setSubstitutions}
|
||||
suggestions={suggestions}
|
||||
/>
|
||||
</TabPanel>
|
||||
) : null}
|
||||
</Tabs>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgEditOperation;
|
|
@ -1,28 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import PickMultiOperation from '@/components/select/PickMultiOperation';
|
||||
import FlexColumn from '@/components/ui/FlexColumn';
|
||||
import Label from '@/components/ui/Label';
|
||||
import { IOperationSchema, OperationID } from '@/models/oss';
|
||||
|
||||
interface TabArgumentsProps {
|
||||
oss: IOperationSchema;
|
||||
target: OperationID;
|
||||
inputs: OperationID[];
|
||||
setInputs: React.Dispatch<React.SetStateAction<OperationID[]>>;
|
||||
}
|
||||
|
||||
function TabArguments({ oss, inputs, target, setInputs }: TabArgumentsProps) {
|
||||
const potentialCycle = [target, ...oss.graph.expandAllOutputs([target])];
|
||||
const filtered = oss.items.filter(item => !potentialCycle.includes(item.id));
|
||||
return (
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<FlexColumn>
|
||||
<Label text={`Выбор аргументов: [ ${inputs.length} ]`} />
|
||||
<PickMultiOperation items={filtered} value={inputs} onChange={setInputs} rows={8} />
|
||||
</FlexColumn>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TabArguments;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user