Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
dd7f2124
Commit
dd7f2124
authored
Jan 19, 2026
by
cyhhao
Browse files
merge: resolve conflicts with main
parents
49be9d08
bba5b3c0
Changes
42
Hide whitespace changes
Inline
Side-by-side
frontend/package.json
View file @
dd7f2124
...
@@ -9,7 +9,10 @@
...
@@ -9,7 +9,10 @@
"preview"
:
"vite preview"
,
"preview"
:
"vite preview"
,
"lint"
:
"eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix"
,
"lint"
:
"eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix"
,
"lint:check"
:
"eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts"
,
"lint:check"
:
"eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts"
,
"typecheck"
:
"vue-tsc --noEmit"
"typecheck"
:
"vue-tsc --noEmit"
,
"test"
:
"vitest"
,
"test:run"
:
"vitest run"
,
"test:coverage"
:
"vitest run --coverage"
},
},
"dependencies"
:
{
"dependencies"
:
{
"@lobehub/icons"
:
"^4.0.2"
,
"@lobehub/icons"
:
"^4.0.2"
,
...
@@ -29,17 +32,21 @@
...
@@ -29,17 +32,21 @@
"@types/file-saver"
:
"^2.0.7"
,
"@types/file-saver"
:
"^2.0.7"
,
"@types/mdx"
:
"^2.0.13"
,
"@types/mdx"
:
"^2.0.13"
,
"@types/node"
:
"^20.10.5"
,
"@types/node"
:
"^20.10.5"
,
"@vitejs/plugin-vue"
:
"^5.2.3"
,
"autoprefixer"
:
"^10.4.16"
,
"@typescript-eslint/eslint-plugin"
:
"^7.18.0"
,
"@typescript-eslint/eslint-plugin"
:
"^7.18.0"
,
"@typescript-eslint/parser"
:
"^7.18.0"
,
"@typescript-eslint/parser"
:
"^7.18.0"
,
"@vitejs/plugin-vue"
:
"^5.2.3"
,
"@vitest/coverage-v8"
:
"^2.1.9"
,
"@vue/test-utils"
:
"^2.4.6"
,
"autoprefixer"
:
"^10.4.16"
,
"eslint"
:
"^8.57.0"
,
"eslint"
:
"^8.57.0"
,
"eslint-plugin-vue"
:
"^9.25.0"
,
"eslint-plugin-vue"
:
"^9.25.0"
,
"jsdom"
:
"^24.1.3"
,
"postcss"
:
"^8.4.32"
,
"postcss"
:
"^8.4.32"
,
"tailwindcss"
:
"^3.4.0"
,
"tailwindcss"
:
"^3.4.0"
,
"typescript"
:
"~5.6.0"
,
"typescript"
:
"~5.6.0"
,
"vite"
:
"^5.0.10"
,
"vite"
:
"^5.0.10"
,
"vite-plugin-checker"
:
"^0.9.1"
,
"vite-plugin-checker"
:
"^0.9.1"
,
"vitest"
:
"^2.1.9"
,
"vue-tsc"
:
"^2.2.0"
"vue-tsc"
:
"^2.2.0"
}
}
}
}
frontend/pnpm-lock.yaml
View file @
dd7f2124
...
@@ -63,6 +63,12 @@ importers:
...
@@ -63,6 +63,12 @@ importers:
'@vitejs/plugin-vue':
'@vitejs/plugin-vue':
specifier: ^5.2.3
specifier: ^5.2.3
version: 5.2.4(vite@5.4.21(@types/node@20.19.27))(vue@3.5.26(typescript@5.6.3))
version: 5.2.4(vite@5.4.21(@types/node@20.19.27))(vue@3.5.26(typescript@5.6.3))
'@vitest/coverage-v8':
specifier: ^2.1.9
version: 2.1.9(vitest@2.1.9(@types/node@20.19.27)(jsdom@24.1.3))
'@vue/test-utils':
specifier: ^2.4.6
version: 2.4.6
autoprefixer:
autoprefixer:
specifier: ^10.4.16
specifier: ^10.4.16
version: 10.4.23(postcss@8.5.6)
version: 10.4.23(postcss@8.5.6)
...
@@ -72,6 +78,9 @@ importers:
...
@@ -72,6 +78,9 @@ importers:
eslint-plugin-vue:
eslint-plugin-vue:
specifier: ^9.25.0
specifier: ^9.25.0
version: 9.33.0(eslint@8.57.1)
version: 9.33.0(eslint@8.57.1)
jsdom:
specifier: ^24.1.3
version: 24.1.3
postcss:
postcss:
specifier: ^8.4.32
specifier: ^8.4.32
version: 8.5.6
version: 8.5.6
...
@@ -87,6 +96,9 @@ importers:
...
@@ -87,6 +96,9 @@ importers:
vite-plugin-checker:
vite-plugin-checker:
specifier: ^0.9.1
specifier: ^0.9.1
version: 0.9.3(eslint@8.57.1)(optionator@0.9.4)(typescript@5.6.3)(vite@5.4.21(@types/node@20.19.27))(vue-tsc@2.2.12(typescript@5.6.3))
version: 0.9.3(eslint@8.57.1)(optionator@0.9.4)(typescript@5.6.3)(vite@5.4.21(@types/node@20.19.27))(vue-tsc@2.2.12(typescript@5.6.3))
vitest:
specifier: ^2.1.9
version: 2.1.9(@types/node@20.19.27)(jsdom@24.1.3)
vue-tsc:
vue-tsc:
specifier: ^2.2.0
specifier: ^2.2.0
version: 2.2.12(typescript@5.6.3)
version: 2.2.12(typescript@5.6.3)
...
@@ -97,6 +109,10 @@ packages:
...
@@ -97,6 +109,10 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
engines: {node: '>=10'}
'@ampproject/remapping@2.3.0':
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
'@ant-design/colors@8.0.0':
'@ant-design/colors@8.0.0':
resolution: {integrity: sha512-6YzkKCw30EI/E9kHOIXsQDHmMvTllT8STzjMb4K2qzit33RW2pqCJP0sk+hidBntXxE+Vz4n1+RvCTfBw6OErw==}
resolution: {integrity: sha512-6YzkKCw30EI/E9kHOIXsQDHmMvTllT8STzjMb4K2qzit33RW2pqCJP0sk+hidBntXxE+Vz4n1+RvCTfBw6OErw==}
...
@@ -135,6 +151,9 @@ packages:
...
@@ -135,6 +151,9 @@ packages:
'@antfu/install-pkg@1.1.0':
'@antfu/install-pkg@1.1.0':
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
'@asamuzakjp/css-color@3.2.0':
resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==}
'@babel/code-frame@7.27.1':
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
engines: {node: '>=6.9.0'}
...
@@ -201,6 +220,9 @@ packages:
...
@@ -201,6 +220,9 @@ packages:
'@types/react':
'@types/react':
optional: true
optional: true
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
'@braintree/sanitize-url@7.1.1':
'@braintree/sanitize-url@7.1.1':
resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==}
resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==}
...
@@ -219,6 +241,34 @@ packages:
...
@@ -219,6 +241,34 @@ packages:
'@chevrotain/utils@11.0.3':
'@chevrotain/utils@11.0.3':
resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==}
resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==}
'@csstools/color-helpers@5.1.0':
resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==}
engines: {node: '>=18'}
'@csstools/css-calc@2.1.4':
resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==}
engines: {node: '>=18'}
peerDependencies:
'@csstools/css-parser-algorithms': ^3.0.5
'@csstools/css-tokenizer': ^3.0.4
'@csstools/css-color-parser@3.1.0':
resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==}
engines: {node: '>=18'}
peerDependencies:
'@csstools/css-parser-algorithms': ^3.0.5
'@csstools/css-tokenizer': ^3.0.4
'@csstools/css-parser-algorithms@3.0.5':
resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
engines: {node: '>=18'}
peerDependencies:
'@csstools/css-tokenizer': ^3.0.4
'@csstools/css-tokenizer@3.0.4':
resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
engines: {node: '>=18'}
'@dnd-kit/accessibility@3.1.1':
'@dnd-kit/accessibility@3.1.1':
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
peerDependencies:
peerDependencies:
...
@@ -523,6 +573,14 @@ packages:
...
@@ -523,6 +573,14 @@ packages:
resolution: {integrity: sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==}
resolution: {integrity: sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==}
engines: {node: '>= 16'}
engines: {node: '>= 16'}
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
'@istanbuljs/schema@0.1.3':
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
engines: {node: '>=8'}
'@jridgewell/gen-mapping@0.3.13':
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
...
@@ -596,6 +654,13 @@ packages:
...
@@ -596,6 +654,13 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
engines: {node: '>= 8'}
'@one-ini/wasm@0.1.1':
resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
'@primer/octicons@19.21.1':
'@primer/octicons@19.21.1':
resolution: {integrity: sha512-7tgtBkCNcg75YJnckinzvES+uxysYQCe+CHSEnzr3VYgxttzKRvfmrnVogl3aEuHCQP4xhiE9k2lFDhYwGtTzQ==}
resolution: {integrity: sha512-7tgtBkCNcg75YJnckinzvES+uxysYQCe+CHSEnzr3VYgxttzKRvfmrnVogl3aEuHCQP4xhiE9k2lFDhYwGtTzQ==}
...
@@ -1505,6 +1570,44 @@ packages:
...
@@ -1505,6 +1570,44 @@ packages:
vite: ^5.0.0 || ^6.0.0
vite: ^5.0.0 || ^6.0.0
vue: ^3.2.25
vue: ^3.2.25
'@vitest/coverage-v8@2.1.9':
resolution: {integrity: sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ==}
peerDependencies:
'@vitest/browser': 2.1.9
vitest: 2.1.9
peerDependenciesMeta:
'@vitest/browser':
optional: true
'@vitest/expect@2.1.9':
resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==}
'@vitest/mocker@2.1.9':
resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==}
peerDependencies:
msw: ^2.4.9
vite: ^5.0.0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
'@vitest/pretty-format@2.1.9':
resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==}
'@vitest/runner@2.1.9':
resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==}
'@vitest/snapshot@2.1.9':
resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==}
'@vitest/spy@2.1.9':
resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==}
'@vitest/utils@2.1.9':
resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==}
'@volar/language-core@2.4.15':
'@volar/language-core@2.4.15':
resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==}
resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==}
...
@@ -1557,6 +1660,9 @@ packages:
...
@@ -1557,6 +1660,9 @@ packages:
'@vue/shared@3.5.26':
'@vue/shared@3.5.26':
resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==}
resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==}
'@vue/test-utils@2.4.6':
resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==}
'@vueuse/core@10.11.1':
'@vueuse/core@10.11.1':
resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
...
@@ -1566,6 +1672,10 @@ packages:
...
@@ -1566,6 +1672,10 @@ packages:
'@vueuse/shared@10.11.1':
'@vueuse/shared@10.11.1':
resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
abbrev@2.0.0:
resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
acorn-jsx@5.3.2:
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
peerDependencies:
...
@@ -1580,6 +1690,10 @@ packages:
...
@@ -1580,6 +1690,10 @@ packages:
resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
engines: {node: '>=0.8'}
engines: {node: '>=0.8'}
agent-base@7.1.4:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'}
ahooks@3.9.6:
ahooks@3.9.6:
resolution: {integrity: sha512-Mr7f05swd5SmKlR9SZo5U6M0LsL4ErweLzpdgXjA1JPmnZ78Vr6wzx0jUtvoxrcqGKYnX0Yjc02iEASVxHFPjQ==}
resolution: {integrity: sha512-Mr7f05swd5SmKlR9SZo5U6M0LsL4ErweLzpdgXjA1JPmnZ78Vr6wzx0jUtvoxrcqGKYnX0Yjc02iEASVxHFPjQ==}
peerDependencies:
peerDependencies:
...
@@ -1604,6 +1718,10 @@ packages:
...
@@ -1604,6 +1718,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
engines: {node: '>=8'}
ansi-styles@6.2.3:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
antd-style@4.1.0:
antd-style@4.1.0:
resolution: {integrity: sha512-vnPBGg0OVlSz90KRYZhxd89aZiOImTiesF+9MQqN8jsLGZUQTjbP04X9jTdEfsztKUuMbBWg/RmB/wHTakbtMQ==}
resolution: {integrity: sha512-vnPBGg0OVlSz90KRYZhxd89aZiOImTiesF+9MQqN8jsLGZUQTjbP04X9jTdEfsztKUuMbBWg/RmB/wHTakbtMQ==}
peerDependencies:
peerDependencies:
...
@@ -1633,6 +1751,10 @@ packages:
...
@@ -1633,6 +1751,10 @@ packages:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
engines: {node: '>=8'}
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
assign-symbols@1.0.0:
assign-symbols@1.0.0:
resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==}
resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
...
@@ -1694,6 +1816,10 @@ packages:
...
@@ -1694,6 +1816,10 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
hasBin: true
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
call-bind-apply-helpers@1.0.2:
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
engines: {node: '>= 0.4'}
...
@@ -1716,6 +1842,10 @@ packages:
...
@@ -1716,6 +1842,10 @@ packages:
resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==}
resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==}
engines: {node: '>=0.8'}
engines: {node: '>=0.8'}
chai@5.3.3:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'}
chalk@4.1.2:
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
engines: {node: '>=10'}
...
@@ -1736,6 +1866,10 @@ packages:
...
@@ -1736,6 +1866,10 @@ packages:
resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==}
resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==}
engines: {pnpm: '>=8'}
engines: {pnpm: '>=8'}
check-error@2.1.3:
resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
engines: {node: '>= 16'}
chevrotain-allstar@0.3.1:
chevrotain-allstar@0.3.1:
resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==}
resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==}
peerDependencies:
peerDependencies:
...
@@ -1793,6 +1927,10 @@ packages:
...
@@ -1793,6 +1927,10 @@ packages:
comma-separated-tokens@2.0.3:
comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
commander@10.0.1:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
engines: {node: '>=14'}
commander@4.1.1:
commander@4.1.1:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
engines: {node: '>= 6'}
...
@@ -1814,6 +1952,9 @@ packages:
...
@@ -1814,6 +1952,9 @@ packages:
confbox@0.1.8:
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
config-chain@1.1.13:
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
convert-source-map@1.9.0:
convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
...
@@ -1841,6 +1982,10 @@ packages:
...
@@ -1841,6 +1982,10 @@ packages:
engines: {node: '>=4'}
engines: {node: '>=4'}
hasBin: true
hasBin: true
cssstyle@4.6.0:
resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==}
engines: {node: '>=18'}
csstype@3.2.3:
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
...
@@ -2000,6 +2145,10 @@ packages:
...
@@ -2000,6 +2145,10 @@ packages:
dagre-d3-es@7.0.13:
dagre-d3-es@7.0.13:
resolution: {integrity: sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==}
resolution: {integrity: sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==}
data-urls@5.0.0:
resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
engines: {node: '>=18'}
dayjs@1.11.19:
dayjs@1.11.19:
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
...
@@ -2015,6 +2164,9 @@ packages:
...
@@ -2015,6 +2164,9 @@ packages:
supports-color:
supports-color:
optional: true
optional: true
decimal.js@10.6.0:
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
decode-named-character-reference@1.2.0:
decode-named-character-reference@1.2.0:
resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==}
resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==}
...
@@ -2022,6 +2174,10 @@ packages:
...
@@ -2022,6 +2174,10 @@ packages:
resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==}
resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==}
engines: {node: '>=14.16'}
engines: {node: '>=14.16'}
deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
deep-is@0.1.4:
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
...
@@ -2063,6 +2219,14 @@ packages:
...
@@ -2063,6 +2219,14 @@ packages:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
engines: {node: '>= 0.4'}
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
editorconfig@1.0.4:
resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==}
engines: {node: '>=14'}
hasBin: true
electron-to-chromium@1.5.267:
electron-to-chromium@1.5.267:
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
...
@@ -2072,6 +2236,12 @@ packages:
...
@@ -2072,6 +2236,12 @@ packages:
emoji-regex@10.6.0:
emoji-regex@10.6.0:
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
entities@6.0.1:
entities@6.0.1:
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
engines: {node: '>=0.12'}
engines: {node: '>=0.12'}
...
@@ -2091,6 +2261,9 @@ packages:
...
@@ -2091,6 +2261,9 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
engines: {node: '>= 0.4'}
es-module-lexer@1.7.0:
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
es-object-atoms@1.1.1:
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
engines: {node: '>= 0.4'}
...
@@ -2189,6 +2362,10 @@ packages:
...
@@ -2189,6 +2362,10 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
extend-shallow@2.0.1:
extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
...
@@ -2271,6 +2448,10 @@ packages:
...
@@ -2271,6 +2448,10 @@ packages:
resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==}
resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
form-data@4.0.5:
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
engines: {node: '>= 6'}
...
@@ -2334,6 +2515,10 @@ packages:
...
@@ -2334,6 +2515,10 @@ packages:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
engines: {node: '>=10.13.0'}
glob@10.5.0:
resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==}
hasBin: true
glob@7.2.3:
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
deprecated: Glob versions prior to v9 are no longer supported
...
@@ -2421,12 +2606,27 @@ packages:
...
@@ -2421,12 +2606,27 @@ packages:
hoist-non-react-statics@3.3.2:
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
html-encoding-sniffer@4.0.0:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
engines: {node: '>=18'}
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
html-url-attributes@3.0.1:
html-url-attributes@3.0.1:
resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
html-void-elements@3.0.0:
html-void-elements@3.0.0:
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
https-proxy-agent@7.0.6:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
iconv-lite@0.6.3:
iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
...
@@ -2453,6 +2653,9 @@ packages:
...
@@ -2453,6 +2653,9 @@ packages:
inherits@2.0.4:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
inline-style-parser@0.2.7:
inline-style-parser@0.2.7:
resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
...
@@ -2499,6 +2702,10 @@ packages:
...
@@ -2499,6 +2702,10 @@ packages:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
is-glob@4.0.3:
is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
...
@@ -2525,6 +2732,9 @@ packages:
...
@@ -2525,6 +2732,9 @@ packages:
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
is-potential-custom-element-name@1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
isexe@2.0.0:
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
...
@@ -2532,10 +2742,34 @@ packages:
...
@@ -2532,10 +2742,34 @@ packages:
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
istanbul-lib-coverage@3.2.2:
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
engines: {node: '>=8'}
istanbul-lib-report@3.0.1:
resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
engines: {node: '>=10'}
istanbul-lib-source-maps@5.0.6:
resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
engines: {node: '>=10'}
istanbul-reports@3.2.0:
resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
engines: {node: '>=8'}
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
jiti@1.21.7:
jiti@1.21.7:
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
hasBin: true
hasBin: true
js-beautify@1.15.4:
resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
engines: {node: '>=14'}
hasBin: true
js-cookie@3.0.5:
js-cookie@3.0.5:
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
engines: {node: '>=14'}
engines: {node: '>=14'}
...
@@ -2547,6 +2781,15 @@ packages:
...
@@ -2547,6 +2781,15 @@ packages:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
hasBin: true
jsdom@24.1.3:
resolution: {integrity: sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
peerDependenciesMeta:
canvas:
optional: true
jsesc@3.1.0:
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
engines: {node: '>=6'}
...
@@ -2636,6 +2879,12 @@ packages:
...
@@ -2636,6 +2879,12 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
hasBin: true
loupe@3.2.1:
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lucide-react@0.469.0:
lucide-react@0.469.0:
resolution: {integrity: sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==}
resolution: {integrity: sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==}
peerDependencies:
peerDependencies:
...
@@ -2649,6 +2898,13 @@ packages:
...
@@ -2649,6 +2898,13 @@ packages:
magic-string@0.30.21:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
magicast@0.3.5:
resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
make-dir@4.0.0:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
markdown-extensions@2.0.0:
markdown-extensions@2.0.0:
resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==}
resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==}
engines: {node: '>=16'}
engines: {node: '>=16'}
...
@@ -2877,10 +3133,18 @@ packages:
...
@@ -2877,10 +3133,18 @@ packages:
minimatch@3.1.2:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@9.0.1:
resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
engines: {node: '>=16 || 14 >=14.17'}
minimatch@9.0.5:
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
engines: {node: '>=16 || 14 >=14.17'}
minipass@7.1.2:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
mixin-deep@1.3.2:
mixin-deep@1.3.2:
resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
...
@@ -2928,6 +3192,11 @@ packages:
...
@@ -2928,6 +3192,11 @@ packages:
node-releases@2.0.27:
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
nopt@7.2.1:
resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
hasBin: true
normalize-path@3.0.0:
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
...
@@ -2942,6 +3211,9 @@ packages:
...
@@ -2942,6 +3211,9 @@ packages:
numeral@2.0.6:
numeral@2.0.6:
resolution: {integrity: sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==}
resolution: {integrity: sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==}
nwsapi@2.2.23:
resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==}
object-assign@4.1.1:
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
engines: {node: '>=0.10.0'}
...
@@ -2975,6 +3247,9 @@ packages:
...
@@ -2975,6 +3247,9 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
engines: {node: '>=10'}
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
package-manager-detector@1.6.0:
package-manager-detector@1.6.0:
resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==}
resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==}
...
@@ -3017,13 +3292,24 @@ packages:
...
@@ -3017,13 +3292,24 @@ packages:
path-parse@1.0.7:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
path-scurry@1.11.1:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
path-type@4.0.0:
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
engines: {node: '>=8'}
pathe@1.1.2:
resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
pathe@2.0.3:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
pathval@2.0.1:
resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
engines: {node: '>= 14.16'}
picocolors@1.1.1:
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
...
@@ -3122,9 +3408,15 @@ packages:
...
@@ -3122,9 +3408,15 @@ packages:
property-information@7.1.0:
property-information@7.1.0:
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
proxy-from-env@1.1.0:
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
psl@1.15.0:
resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
punycode@2.3.1:
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
engines: {node: '>=6'}
...
@@ -3133,6 +3425,9 @@ packages:
...
@@ -3133,6 +3425,9 @@ packages:
resolution: {integrity: sha512-5fBfMOcDi5SA9qj5jZhWAcTtDfKF5WFdd2uD9nVNlbxVv1baq65aALy6qofpNEGELHvisjjasxQp7BlM9gvMzw==}
resolution: {integrity: sha512-5fBfMOcDi5SA9qj5jZhWAcTtDfKF5WFdd2uD9nVNlbxVv1baq65aALy6qofpNEGELHvisjjasxQp7BlM9gvMzw==}
engines: {node: '>=18'}
engines: {node: '>=18'}
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
queue-microtask@1.2.3:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
...
@@ -3369,6 +3664,9 @@ packages:
...
@@ -3369,6 +3664,9 @@ packages:
remark-stringify@11.0.0:
remark-stringify@11.0.0:
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
reselect@5.1.1:
reselect@5.1.1:
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
...
@@ -3404,6 +3702,12 @@ packages:
...
@@ -3404,6 +3702,12 @@ packages:
roughjs@4.6.6:
roughjs@4.6.6:
resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==}
resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==}
rrweb-cssom@0.7.1:
resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==}
rrweb-cssom@0.8.0:
resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
run-parallel@1.2.0:
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
...
@@ -3413,6 +3717,10 @@ packages:
...
@@ -3413,6 +3717,10 @@ packages:
safer-buffer@2.1.2:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
saxes@6.0.0:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
scheduler@0.27.0:
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
...
@@ -3457,6 +3765,13 @@ packages:
...
@@ -3457,6 +3765,13 @@ packages:
shiki@3.20.0:
shiki@3.20.0:
resolution: {integrity: sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg==}
resolution: {integrity: sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg==}
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
slash@3.0.0:
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
engines: {node: '>=8'}
...
@@ -3488,9 +3803,23 @@ packages:
...
@@ -3488,9 +3803,23 @@ packages:
resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
engines: {node: '>=0.8'}
engines: {node: '>=0.8'}
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
std-env@3.10.0:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
string-convert@0.2.1:
string-convert@0.2.1:
resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==}
resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==}
string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
stringify-entities@4.0.4:
stringify-entities@4.0.4:
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
...
@@ -3536,6 +3865,9 @@ packages:
...
@@ -3536,6 +3865,9 @@ packages:
peerDependencies:
peerDependencies:
react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
tabbable@6.4.0:
tabbable@6.4.0:
resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==}
resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==}
...
@@ -3544,6 +3876,10 @@ packages:
...
@@ -3544,6 +3876,10 @@ packages:
engines: {node: '>=14.0.0'}
engines: {node: '>=14.0.0'}
hasBin: true
hasBin: true
test-exclude@7.0.1:
resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
engines: {node: '>=18'}
text-table@0.2.0:
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
...
@@ -3561,6 +3897,12 @@ packages:
...
@@ -3561,6 +3897,12 @@ packages:
tiny-invariant@1.3.3:
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
tinyexec@0.3.2:
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
tinyexec@1.0.2:
tinyexec@1.0.2:
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
engines: {node: '>=18'}
engines: {node: '>=18'}
...
@@ -3569,6 +3911,18 @@ packages:
...
@@ -3569,6 +3911,18 @@ packages:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
engines: {node: '>=12.0.0'}
tinypool@1.1.1:
resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
engines: {node: ^18.0.0 || >=20.0.0}
tinyrainbow@1.2.0:
resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
engines: {node: '>=14.0.0'}
tinyspy@3.0.2:
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
to-regex-range@5.0.1:
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
engines: {node: '>=8.0'}
...
@@ -3576,6 +3930,14 @@ packages:
...
@@ -3576,6 +3930,14 @@ packages:
to-vfile@8.0.0:
to-vfile@8.0.0:
resolution: {integrity: sha512-IcmH1xB5576MJc9qcfEC/m/nQCFt3fzMHz45sSlgJyTWjRbKW1HAkJpuf3DgE57YzIlZcwcBZA5ENQbBo4aLkg==}
resolution: {integrity: sha512-IcmH1xB5576MJc9qcfEC/m/nQCFt3fzMHz45sSlgJyTWjRbKW1HAkJpuf3DgE57YzIlZcwcBZA5ENQbBo4aLkg==}
tough-cookie@4.1.4:
resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
engines: {node: '>=6'}
tr46@5.1.1:
resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
engines: {node: '>=18'}
trim-lines@3.0.1:
trim-lines@3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
...
@@ -3655,6 +4017,10 @@ packages:
...
@@ -3655,6 +4017,10 @@ packages:
unist-util-visit@5.0.0:
unist-util-visit@5.0.0:
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
update-browserslist-db@1.2.3:
update-browserslist-db@1.2.3:
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
hasBin: true
hasBin: true
...
@@ -3668,6 +4034,9 @@ packages:
...
@@ -3668,6 +4034,9 @@ packages:
resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==}
resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
use-merge-value@1.2.0:
use-merge-value@1.2.0:
resolution: {integrity: sha512-DXgG0kkgJN45TcyoXL49vJnn55LehnrmoHc7MbKi+QDBvr8dsesqws8UlyIWGHMR+JXgxc1nvY+jDGMlycsUcw==}
resolution: {integrity: sha512-DXgG0kkgJN45TcyoXL49vJnn55LehnrmoHc7MbKi+QDBvr8dsesqws8UlyIWGHMR+JXgxc1nvY+jDGMlycsUcw==}
peerDependencies:
peerDependencies:
...
@@ -3701,6 +4070,11 @@ packages:
...
@@ -3701,6 +4070,11 @@ packages:
vfile@6.0.3:
vfile@6.0.3:
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
vite-node@2.1.9:
resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
vite-plugin-checker@0.9.3:
vite-plugin-checker@0.9.3:
resolution: {integrity: sha512-Tf7QBjeBtG7q11zG0lvoF38/2AVUzzhMNu+Wk+mcsJ00Rk/FpJ4rmUviVJpzWkagbU13cGXvKpt7CMiqtxVTbQ==}
resolution: {integrity: sha512-Tf7QBjeBtG7q11zG0lvoF38/2AVUzzhMNu+Wk+mcsJ00Rk/FpJ4rmUviVJpzWkagbU13cGXvKpt7CMiqtxVTbQ==}
engines: {node: '>=14.16'}
engines: {node: '>=14.16'}
...
@@ -3766,6 +4140,31 @@ packages:
...
@@ -3766,6 +4140,31 @@ packages:
terser:
terser:
optional: true
optional: true
vitest@2.1.9:
resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/node': ^18.0.0 || >=20.0.0
'@vitest/browser': 2.1.9
'@vitest/ui': 2.1.9
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
'@types/node':
optional: true
'@vitest/browser':
optional: true
'@vitest/ui':
optional: true
happy-dom:
optional: true
jsdom:
optional: true
vscode-jsonrpc@8.2.0:
vscode-jsonrpc@8.2.0:
resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
engines: {node: '>=14.0.0'}
engines: {node: '>=14.0.0'}
...
@@ -3795,6 +4194,9 @@ packages:
...
@@ -3795,6 +4194,9 @@ packages:
chart.js: ^4.1.1
chart.js: ^4.1.1
vue: ^3.0.0-0 || ^2.7.0
vue: ^3.0.0-0 || ^2.7.0
vue-component-type-helpers@2.2.12:
resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==}
vue-demi@0.14.10:
vue-demi@0.14.10:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'}
engines: {node: '>=12'}
...
@@ -3837,14 +4239,40 @@ packages:
...
@@ -3837,14 +4239,40 @@ packages:
typescript:
typescript:
optional: true
optional: true
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
web-namespaces@2.0.1:
web-namespaces@2.0.1:
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
webidl-conversions@7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
whatwg-mimetype@4.0.0:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}
whatwg-url@14.2.0:
resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
engines: {node: '>=18'}
which@2.0.2:
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
engines: {node: '>= 8'}
hasBin: true
hasBin: true
why-is-node-running@2.3.0:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
wmf@1.0.2:
wmf@1.0.2:
resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
engines: {node: '>=0.8'}
engines: {node: '>=0.8'}
...
@@ -3857,9 +4285,29 @@ packages:
...
@@ -3857,9 +4285,29 @@ packages:
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
engines: {node: '>=0.8'}
engines: {node: '>=0.8'}
wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
wrappy@1.0.2:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
ws@8.19.0:
resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
xlsx@0.18.5:
xlsx@0.18.5:
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
engines: {node: '>=0.8'}
engines: {node: '>=0.8'}
...
@@ -3869,6 +4317,13 @@ packages:
...
@@ -3869,6 +4317,13 @@ packages:
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
engines: {node: '>=12'}
engines: {node: '>=12'}
xml-name-validator@5.0.0:
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
engines: {node: '>=18'}
xmlchars@2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
yaml@1.10.2:
yaml@1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
engines: {node: '>= 6'}
...
@@ -3893,6 +4348,11 @@ snapshots:
...
@@ -3893,6 +4348,11 @@ snapshots:
'@alloc/quick-lru@5.2.0': {}
'@alloc/quick-lru@5.2.0': {}
'@ampproject/remapping@2.3.0':
dependencies:
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
'@ant-design/colors@8.0.0':
'@ant-design/colors@8.0.0':
dependencies:
dependencies:
'@ant-design/fast-color': 3.0.0
'@ant-design/fast-color': 3.0.0
...
@@ -3944,6 +4404,14 @@ snapshots:
...
@@ -3944,6 +4404,14 @@ snapshots:
package-manager-detector: 1.6.0
package-manager-detector: 1.6.0
tinyexec: 1.0.2
tinyexec: 1.0.2
'@asamuzakjp/css-color@3.2.0':
dependencies:
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
lru-cache: 10.4.3
'@babel/code-frame@7.27.1':
'@babel/code-frame@7.27.1':
dependencies:
dependencies:
'@babel/helper-validator-identifier': 7.28.5
'@babel/helper-validator-identifier': 7.28.5
...
@@ -4025,6 +4493,8 @@ snapshots:
...
@@ -4025,6 +4493,8 @@ snapshots:
optionalDependencies:
optionalDependencies:
'@types/react': 19.2.7
'@types/react': 19.2.7
'@bcoe/v8-coverage@0.2.3': {}
'@braintree/sanitize-url@7.1.1': {}
'@braintree/sanitize-url@7.1.1': {}
'@chevrotain/cst-dts-gen@11.0.3':
'@chevrotain/cst-dts-gen@11.0.3':
...
@@ -4044,6 +4514,26 @@ snapshots:
...
@@ -4044,6 +4514,26 @@ snapshots:
'@chevrotain/utils@11.0.3': {}
'@chevrotain/utils@11.0.3': {}
'@csstools/color-helpers@5.1.0': {}
'@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
'@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/color-helpers': 5.1.0
'@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4
'@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
dependencies:
'@csstools/css-tokenizer': 3.0.4
'@csstools/css-tokenizer@3.0.4': {}
'@dnd-kit/accessibility@3.1.1(react@19.2.3)':
'@dnd-kit/accessibility@3.1.1(react@19.2.3)':
dependencies:
dependencies:
react: 19.2.3
react: 19.2.3
...
@@ -4320,6 +4810,17 @@ snapshots:
...
@@ -4320,6 +4810,17 @@ snapshots:
'@intlify/shared@9.14.5': {}
'@intlify/shared@9.14.5': {}
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
string-width-cjs: string-width@4.2.3
strip-ansi: 7.1.2
strip-ansi-cjs: strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
'@istanbuljs/schema@0.1.3': {}
'@jridgewell/gen-mapping@0.3.13':
'@jridgewell/gen-mapping@0.3.13':
dependencies:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/sourcemap-codec': 1.5.5
...
@@ -4505,6 +5006,11 @@ snapshots:
...
@@ -4505,6 +5006,11 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
'@nodelib/fs.scandir': 2.1.5
fastq: 1.20.1
fastq: 1.20.1
'@one-ini/wasm@0.1.1': {}
'@pkgjs/parseargs@0.11.0':
optional: true
'@primer/octicons@19.21.1':
'@primer/octicons@19.21.1':
dependencies:
dependencies:
object-assign: 4.1.1
object-assign: 4.1.1
...
@@ -5439,6 +5945,64 @@ snapshots:
...
@@ -5439,6 +5945,64 @@ snapshots:
vite: 5.4.21(@types/node@20.19.27)
vite: 5.4.21(@types/node@20.19.27)
vue: 3.5.26(typescript@5.6.3)
vue: 3.5.26(typescript@5.6.3)
'@vitest/coverage-v8@2.1.9(vitest@2.1.9(@types/node@20.19.27)(jsdom@24.1.3))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 0.2.3
debug: 4.4.3
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
istanbul-reports: 3.2.0
magic-string: 0.30.21
magicast: 0.3.5
std-env: 3.10.0
test-exclude: 7.0.1
tinyrainbow: 1.2.0
vitest: 2.1.9(@types/node@20.19.27)(jsdom@24.1.3)
transitivePeerDependencies:
- supports-color
'@vitest/expect@2.1.9':
dependencies:
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
chai: 5.3.3
tinyrainbow: 1.2.0
'@vitest/mocker@2.1.9(vite@5.4.21(@types/node@20.19.27))':
dependencies:
'@vitest/spy': 2.1.9
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 5.4.21(@types/node@20.19.27)
'@vitest/pretty-format@2.1.9':
dependencies:
tinyrainbow: 1.2.0
'@vitest/runner@2.1.9':
dependencies:
'@vitest/utils': 2.1.9
pathe: 1.1.2
'@vitest/snapshot@2.1.9':
dependencies:
'@vitest/pretty-format': 2.1.9
magic-string: 0.30.21
pathe: 1.1.2
'@vitest/spy@2.1.9':
dependencies:
tinyspy: 3.0.2
'@vitest/utils@2.1.9':
dependencies:
'@vitest/pretty-format': 2.1.9
loupe: 3.2.1
tinyrainbow: 1.2.0
'@volar/language-core@2.4.15':
'@volar/language-core@2.4.15':
dependencies:
dependencies:
'@volar/source-map': 2.4.15
'@volar/source-map': 2.4.15
...
@@ -5525,6 +6089,11 @@ snapshots:
...
@@ -5525,6 +6089,11 @@ snapshots:
'@vue/shared@3.5.26': {}
'@vue/shared@3.5.26': {}
'@vue/test-utils@2.4.6':
dependencies:
js-beautify: 1.15.4
vue-component-type-helpers: 2.2.12
'@vueuse/core@10.11.1(vue@3.5.26(typescript@5.6.3))':
'@vueuse/core@10.11.1(vue@3.5.26(typescript@5.6.3))':
dependencies:
dependencies:
'@types/web-bluetooth': 0.0.20
'@types/web-bluetooth': 0.0.20
...
@@ -5544,6 +6113,8 @@ snapshots:
...
@@ -5544,6 +6113,8 @@ snapshots:
- '@vue/composition-api'
- '@vue/composition-api'
- vue
- vue
abbrev@2.0.0: {}
acorn-jsx@5.3.2(acorn@8.15.0):
acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
dependencies:
acorn: 8.15.0
acorn: 8.15.0
...
@@ -5552,6 +6123,8 @@ snapshots:
...
@@ -5552,6 +6123,8 @@ snapshots:
adler-32@1.3.1: {}
adler-32@1.3.1: {}
agent-base@7.1.4: {}
ahooks@3.9.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
ahooks@3.9.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
dependencies:
'@babel/runtime': 7.28.4
'@babel/runtime': 7.28.4
...
@@ -5584,6 +6157,8 @@ snapshots:
...
@@ -5584,6 +6157,8 @@ snapshots:
dependencies:
dependencies:
color-convert: 2.0.1
color-convert: 2.0.1
ansi-styles@6.2.3: {}
antd-style@4.1.0(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
antd-style@4.1.0(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
dependencies:
'@ant-design/cssinjs': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
'@ant-design/cssinjs': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
...
@@ -5671,6 +6246,8 @@ snapshots:
...
@@ -5671,6 +6246,8 @@ snapshots:
array-union@2.1.0: {}
array-union@2.1.0: {}
assertion-error@2.0.1: {}
assign-symbols@1.0.0: {}
assign-symbols@1.0.0: {}
astring@1.9.0: {}
astring@1.9.0: {}
...
@@ -5733,6 +6310,8 @@ snapshots:
...
@@ -5733,6 +6310,8 @@ snapshots:
node-releases: 2.0.27
node-releases: 2.0.27
update-browserslist-db: 1.2.3(browserslist@4.28.1)
update-browserslist-db: 1.2.3(browserslist@4.28.1)
cac@6.7.14: {}
call-bind-apply-helpers@1.0.2:
call-bind-apply-helpers@1.0.2:
dependencies:
dependencies:
es-errors: 1.3.0
es-errors: 1.3.0
...
@@ -5751,6 +6330,14 @@ snapshots:
...
@@ -5751,6 +6330,14 @@ snapshots:
adler-32: 1.3.1
adler-32: 1.3.1
crc-32: 1.2.2
crc-32: 1.2.2
chai@5.3.3:
dependencies:
assertion-error: 2.0.1
check-error: 2.1.3
deep-eql: 5.0.2
loupe: 3.2.1
pathval: 2.0.1
chalk@4.1.2:
chalk@4.1.2:
dependencies:
dependencies:
ansi-styles: 4.3.0
ansi-styles: 4.3.0
...
@@ -5768,6 +6355,8 @@ snapshots:
...
@@ -5768,6 +6355,8 @@ snapshots:
dependencies:
dependencies:
'@kurkle/color': 0.3.4
'@kurkle/color': 0.3.4
check-error@2.1.3: {}
chevrotain-allstar@0.3.1(chevrotain@11.0.3):
chevrotain-allstar@0.3.1(chevrotain@11.0.3):
dependencies:
dependencies:
chevrotain: 11.0.3
chevrotain: 11.0.3
...
@@ -5828,6 +6417,8 @@ snapshots:
...
@@ -5828,6 +6417,8 @@ snapshots:
comma-separated-tokens@2.0.3: {}
comma-separated-tokens@2.0.3: {}
commander@10.0.1: {}
commander@4.1.1: {}
commander@4.1.1: {}
commander@7.2.0: {}
commander@7.2.0: {}
...
@@ -5840,6 +6431,11 @@ snapshots:
...
@@ -5840,6 +6431,11 @@ snapshots:
confbox@0.1.8: {}
confbox@0.1.8: {}
config-chain@1.1.13:
dependencies:
ini: 1.3.8
proto-list: 1.2.4
convert-source-map@1.9.0: {}
convert-source-map@1.9.0: {}
cose-base@1.0.3:
cose-base@1.0.3:
...
@@ -5868,6 +6464,11 @@ snapshots:
...
@@ -5868,6 +6464,11 @@ snapshots:
cssesc@3.0.0: {}
cssesc@3.0.0: {}
cssstyle@4.6.0:
dependencies:
'@asamuzakjp/css-color': 3.2.0
rrweb-cssom: 0.8.0
csstype@3.2.3: {}
csstype@3.2.3: {}
cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1):
cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1):
...
@@ -6054,6 +6655,11 @@ snapshots:
...
@@ -6054,6 +6655,11 @@ snapshots:
d3: 7.9.0
d3: 7.9.0
lodash-es: 4.17.22
lodash-es: 4.17.22
data-urls@5.0.0:
dependencies:
whatwg-mimetype: 4.0.0
whatwg-url: 14.2.0
dayjs@1.11.19: {}
dayjs@1.11.19: {}
de-indent@1.0.2: {}
de-indent@1.0.2: {}
...
@@ -6062,12 +6668,16 @@ snapshots:
...
@@ -6062,12 +6668,16 @@ snapshots:
dependencies:
dependencies:
ms: 2.1.3
ms: 2.1.3
decimal.js@10.6.0: {}
decode-named-character-reference@1.2.0:
decode-named-character-reference@1.2.0:
dependencies:
dependencies:
character-entities: 2.0.2
character-entities: 2.0.2
decode-uri-component@0.4.1: {}
decode-uri-component@0.4.1: {}
deep-eql@5.0.2: {}
deep-is@0.1.4: {}
deep-is@0.1.4: {}
delaunator@5.0.1:
delaunator@5.0.1:
...
@@ -6106,12 +6716,25 @@ snapshots:
...
@@ -6106,12 +6716,25 @@ snapshots:
es-errors: 1.3.0
es-errors: 1.3.0
gopd: 1.2.0
gopd: 1.2.0
eastasianwidth@0.2.0: {}
editorconfig@1.0.4:
dependencies:
'@one-ini/wasm': 0.1.1
commander: 10.0.1
minimatch: 9.0.1
semver: 7.7.3
electron-to-chromium@1.5.267: {}
electron-to-chromium@1.5.267: {}
emoji-mart@5.6.0: {}
emoji-mart@5.6.0: {}
emoji-regex@10.6.0: {}
emoji-regex@10.6.0: {}
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
entities@6.0.1: {}
entities@6.0.1: {}
entities@7.0.0: {}
entities@7.0.0: {}
...
@@ -6124,6 +6747,8 @@ snapshots:
...
@@ -6124,6 +6747,8 @@ snapshots:
es-errors@1.3.0: {}
es-errors@1.3.0: {}
es-module-lexer@1.7.0: {}
es-object-atoms@1.1.1:
es-object-atoms@1.1.1:
dependencies:
dependencies:
es-errors: 1.3.0
es-errors: 1.3.0
...
@@ -6300,6 +6925,8 @@ snapshots:
...
@@ -6300,6 +6925,8 @@ snapshots:
esutils@2.0.3: {}
esutils@2.0.3: {}
expect-type@1.3.0: {}
extend-shallow@2.0.1:
extend-shallow@2.0.1:
dependencies:
dependencies:
is-extendable: 0.1.1
is-extendable: 0.1.1
...
@@ -6368,6 +6995,11 @@ snapshots:
...
@@ -6368,6 +6995,11 @@ snapshots:
for-in@1.0.2: {}
for-in@1.0.2: {}
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
form-data@4.0.5:
form-data@4.0.5:
dependencies:
dependencies:
asynckit: 0.4.0
asynckit: 0.4.0
...
@@ -6431,6 +7063,15 @@ snapshots:
...
@@ -6431,6 +7063,15 @@ snapshots:
dependencies:
dependencies:
is-glob: 4.0.3
is-glob: 4.0.3
glob@10.5.0:
dependencies:
foreground-child: 3.3.1
jackspeak: 3.4.3
minimatch: 9.0.5
minipass: 7.1.2
package-json-from-dist: 1.0.1
path-scurry: 1.11.1
glob@7.2.3:
glob@7.2.3:
dependencies:
dependencies:
fs.realpath: 1.0.0
fs.realpath: 1.0.0
...
@@ -6618,10 +7259,30 @@ snapshots:
...
@@ -6618,10 +7259,30 @@ snapshots:
dependencies:
dependencies:
react-is: 16.13.1
react-is: 16.13.1
html-encoding-sniffer@4.0.0:
dependencies:
whatwg-encoding: 3.1.1
html-escaper@2.0.2: {}
html-url-attributes@3.0.1: {}
html-url-attributes@3.0.1: {}
html-void-elements@3.0.0: {}
html-void-elements@3.0.0: {}
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.4
debug: 4.4.3
transitivePeerDependencies:
- supports-color
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.4
debug: 4.4.3
transitivePeerDependencies:
- supports-color
iconv-lite@0.6.3:
iconv-lite@0.6.3:
dependencies:
dependencies:
safer-buffer: 2.1.2
safer-buffer: 2.1.2
...
@@ -6644,6 +7305,8 @@ snapshots:
...
@@ -6644,6 +7305,8 @@ snapshots:
inherits@2.0.4: {}
inherits@2.0.4: {}
ini@1.3.8: {}
inline-style-parser@0.2.7: {}
inline-style-parser@0.2.7: {}
internmap@1.0.1: {}
internmap@1.0.1: {}
...
@@ -6679,6 +7342,8 @@ snapshots:
...
@@ -6679,6 +7342,8 @@ snapshots:
is-extglob@2.1.1: {}
is-extglob@2.1.1: {}
is-fullwidth-code-point@3.0.0: {}
is-glob@4.0.3:
is-glob@4.0.3:
dependencies:
dependencies:
is-extglob: 2.1.1
is-extglob: 2.1.1
...
@@ -6697,12 +7362,49 @@ snapshots:
...
@@ -6697,12 +7362,49 @@ snapshots:
dependencies:
dependencies:
isobject: 3.0.1
isobject: 3.0.1
is-potential-custom-element-name@1.0.1: {}
isexe@2.0.0: {}
isexe@2.0.0: {}
isobject@3.0.1: {}
isobject@3.0.1: {}
istanbul-lib-coverage@3.2.2: {}
istanbul-lib-report@3.0.1:
dependencies:
istanbul-lib-coverage: 3.2.2
make-dir: 4.0.0
supports-color: 7.2.0
istanbul-lib-source-maps@5.0.6:
dependencies:
'@jridgewell/trace-mapping': 0.3.31
debug: 4.4.3
istanbul-lib-coverage: 3.2.2
transitivePeerDependencies:
- supports-color
istanbul-reports@3.2.0:
dependencies:
html-escaper: 2.0.2
istanbul-lib-report: 3.0.1
jackspeak@3.4.3:
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
jiti@1.21.7: {}
jiti@1.21.7: {}
js-beautify@1.15.4:
dependencies:
config-chain: 1.1.13
editorconfig: 1.0.4
glob: 10.5.0
js-cookie: 3.0.5
nopt: 7.2.1
js-cookie@3.0.5: {}
js-cookie@3.0.5: {}
js-tokens@4.0.0: {}
js-tokens@4.0.0: {}
...
@@ -6711,6 +7413,34 @@ snapshots:
...
@@ -6711,6 +7413,34 @@ snapshots:
dependencies:
dependencies:
argparse: 2.0.1
argparse: 2.0.1
jsdom@24.1.3:
dependencies:
cssstyle: 4.6.0
data-urls: 5.0.0
decimal.js: 10.6.0
form-data: 4.0.5
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.23
parse5: 7.3.0
rrweb-cssom: 0.7.1
saxes: 6.0.0
symbol-tree: 3.2.4
tough-cookie: 4.1.4
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.2.0
ws: 8.19.0
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
jsesc@3.1.0: {}
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
json-buffer@3.0.1: {}
...
@@ -6809,6 +7539,10 @@ snapshots:
...
@@ -6809,6 +7539,10 @@ snapshots:
dependencies:
dependencies:
js-tokens: 4.0.0
js-tokens: 4.0.0
loupe@3.2.1: {}
lru-cache@10.4.3: {}
lucide-react@0.469.0(react@19.2.3):
lucide-react@0.469.0(react@19.2.3):
dependencies:
dependencies:
react: 19.2.3
react: 19.2.3
...
@@ -6821,6 +7555,16 @@ snapshots:
...
@@ -6821,6 +7555,16 @@ snapshots:
dependencies:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/sourcemap-codec': 1.5.5
magicast@0.3.5:
dependencies:
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
source-map-js: 1.2.1
make-dir@4.0.0:
dependencies:
semver: 7.7.3
markdown-extensions@2.0.0: {}
markdown-extensions@2.0.0: {}
markdown-table@3.0.4: {}
markdown-table@3.0.4: {}
...
@@ -7351,10 +8095,16 @@ snapshots:
...
@@ -7351,10 +8095,16 @@ snapshots:
dependencies:
dependencies:
brace-expansion: 1.1.12
brace-expansion: 1.1.12
minimatch@9.0.1:
dependencies:
brace-expansion: 2.0.2
minimatch@9.0.5:
minimatch@9.0.5:
dependencies:
dependencies:
brace-expansion: 2.0.2
brace-expansion: 2.0.2
minipass@7.1.2: {}
mixin-deep@1.3.2:
mixin-deep@1.3.2:
dependencies:
dependencies:
for-in: 1.0.2
for-in: 1.0.2
...
@@ -7398,6 +8148,10 @@ snapshots:
...
@@ -7398,6 +8148,10 @@ snapshots:
node-releases@2.0.27: {}
node-releases@2.0.27: {}
nopt@7.2.1:
dependencies:
abbrev: 2.0.0
normalize-path@3.0.0: {}
normalize-path@3.0.0: {}
npm-run-path@6.0.0:
npm-run-path@6.0.0:
...
@@ -7411,6 +8165,8 @@ snapshots:
...
@@ -7411,6 +8165,8 @@ snapshots:
numeral@2.0.6: {}
numeral@2.0.6: {}
nwsapi@2.2.23: {}
object-assign@4.1.1: {}
object-assign@4.1.1: {}
object-hash@3.0.0: {}
object-hash@3.0.0: {}
...
@@ -7446,6 +8202,8 @@ snapshots:
...
@@ -7446,6 +8202,8 @@ snapshots:
dependencies:
dependencies:
p-limit: 3.1.0
p-limit: 3.1.0
package-json-from-dist@1.0.1: {}
package-manager-detector@1.6.0: {}
package-manager-detector@1.6.0: {}
parent-module@1.0.1:
parent-module@1.0.1:
...
@@ -7487,10 +8245,19 @@ snapshots:
...
@@ -7487,10 +8245,19 @@ snapshots:
path-parse@1.0.7: {}
path-parse@1.0.7: {}
path-scurry@1.11.1:
dependencies:
lru-cache: 10.4.3
minipass: 7.1.2
path-type@4.0.0: {}
path-type@4.0.0: {}
pathe@1.1.2: {}
pathe@2.0.3: {}
pathe@2.0.3: {}
pathval@2.0.1: {}
picocolors@1.1.1: {}
picocolors@1.1.1: {}
picomatch@2.3.1: {}
picomatch@2.3.1: {}
...
@@ -7575,8 +8342,14 @@ snapshots:
...
@@ -7575,8 +8342,14 @@ snapshots:
property-information@7.1.0: {}
property-information@7.1.0: {}
proto-list@1.2.4: {}
proxy-from-env@1.1.0: {}
proxy-from-env@1.1.0: {}
psl@1.15.0:
dependencies:
punycode: 2.3.1
punycode@2.3.1: {}
punycode@2.3.1: {}
query-string@9.3.1:
query-string@9.3.1:
...
@@ -7585,6 +8358,8 @@ snapshots:
...
@@ -7585,6 +8358,8 @@ snapshots:
filter-obj: 5.1.0
filter-obj: 5.1.0
split-on-first: 3.0.0
split-on-first: 3.0.0
querystringify@2.2.0: {}
queue-microtask@1.2.3: {}
queue-microtask@1.2.3: {}
rc-collapse@4.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
rc-collapse@4.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
...
@@ -7928,6 +8703,8 @@ snapshots:
...
@@ -7928,6 +8703,8 @@ snapshots:
mdast-util-to-markdown: 2.1.2
mdast-util-to-markdown: 2.1.2
unified: 11.0.5
unified: 11.0.5
requires-port@1.0.0: {}
reselect@5.1.1: {}
reselect@5.1.1: {}
resize-observer-polyfill@1.5.1: {}
resize-observer-polyfill@1.5.1: {}
...
@@ -7983,6 +8760,10 @@ snapshots:
...
@@ -7983,6 +8760,10 @@ snapshots:
points-on-curve: 0.2.0
points-on-curve: 0.2.0
points-on-path: 0.2.1
points-on-path: 0.2.1
rrweb-cssom@0.7.1: {}
rrweb-cssom@0.8.0: {}
run-parallel@1.2.0:
run-parallel@1.2.0:
dependencies:
dependencies:
queue-microtask: 1.2.3
queue-microtask: 1.2.3
...
@@ -7991,6 +8772,10 @@ snapshots:
...
@@ -7991,6 +8772,10 @@ snapshots:
safer-buffer@2.1.2: {}
safer-buffer@2.1.2: {}
saxes@6.0.0:
dependencies:
xmlchars: 2.2.0
scheduler@0.27.0: {}
scheduler@0.27.0: {}
screenfull@5.2.0: {}
screenfull@5.2.0: {}
...
@@ -8034,6 +8819,10 @@ snapshots:
...
@@ -8034,6 +8819,10 @@ snapshots:
'@shikijs/vscode-textmate': 10.0.2
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
'@types/hast': 3.0.4
siginfo@2.0.0: {}
signal-exit@4.1.0: {}
slash@3.0.0: {}
slash@3.0.0: {}
source-map-js@1.2.1: {}
source-map-js@1.2.1: {}
...
@@ -8054,8 +8843,24 @@ snapshots:
...
@@ -8054,8 +8843,24 @@ snapshots:
dependencies:
dependencies:
frac: 1.1.2
frac: 1.1.2
stackback@0.0.2: {}
std-env@3.10.0: {}
string-convert@0.2.1: {}
string-convert@0.2.1: {}
string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
string-width@5.1.2:
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.2
stringify-entities@4.0.4:
stringify-entities@4.0.4:
dependencies:
dependencies:
character-entities-html4: 2.1.0
character-entities-html4: 2.1.0
...
@@ -8105,6 +8910,8 @@ snapshots:
...
@@ -8105,6 +8910,8 @@ snapshots:
react: 19.2.3
react: 19.2.3
use-sync-external-store: 1.6.0(react@19.2.3)
use-sync-external-store: 1.6.0(react@19.2.3)
symbol-tree@3.2.4: {}
tabbable@6.4.0: {}
tabbable@6.4.0: {}
tailwindcss@3.4.19:
tailwindcss@3.4.19:
...
@@ -8135,6 +8942,12 @@ snapshots:
...
@@ -8135,6 +8942,12 @@ snapshots:
- tsx
- tsx
- yaml
- yaml
test-exclude@7.0.1:
dependencies:
'@istanbuljs/schema': 0.1.3
glob: 10.5.0
minimatch: 9.0.5
text-table@0.2.0: {}
text-table@0.2.0: {}
thenify-all@1.6.0:
thenify-all@1.6.0:
...
@@ -8149,6 +8962,10 @@ snapshots:
...
@@ -8149,6 +8962,10 @@ snapshots:
tiny-invariant@1.3.3: {}
tiny-invariant@1.3.3: {}
tinybench@2.9.0: {}
tinyexec@0.3.2: {}
tinyexec@1.0.2: {}
tinyexec@1.0.2: {}
tinyglobby@0.2.15:
tinyglobby@0.2.15:
...
@@ -8156,6 +8973,12 @@ snapshots:
...
@@ -8156,6 +8973,12 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.3)
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
picomatch: 4.0.3
tinypool@1.1.1: {}
tinyrainbow@1.2.0: {}
tinyspy@3.0.2: {}
to-regex-range@5.0.1:
to-regex-range@5.0.1:
dependencies:
dependencies:
is-number: 7.0.0
is-number: 7.0.0
...
@@ -8164,6 +8987,17 @@ snapshots:
...
@@ -8164,6 +8987,17 @@ snapshots:
dependencies:
dependencies:
vfile: 6.0.3
vfile: 6.0.3
tough-cookie@4.1.4:
dependencies:
psl: 1.15.0
punycode: 2.3.1
universalify: 0.2.0
url-parse: 1.5.10
tr46@5.1.1:
dependencies:
punycode: 2.3.1
trim-lines@3.0.1: {}
trim-lines@3.0.1: {}
trough@2.2.0: {}
trough@2.2.0: {}
...
@@ -8243,6 +9077,8 @@ snapshots:
...
@@ -8243,6 +9077,8 @@ snapshots:
unist-util-is: 6.0.1
unist-util-is: 6.0.1
unist-util-visit-parents: 6.0.2
unist-util-visit-parents: 6.0.2
universalify@0.2.0: {}
update-browserslist-db@1.2.3(browserslist@4.28.1):
update-browserslist-db@1.2.3(browserslist@4.28.1):
dependencies:
dependencies:
browserslist: 4.28.1
browserslist: 4.28.1
...
@@ -8255,6 +9091,11 @@ snapshots:
...
@@ -8255,6 +9091,11 @@ snapshots:
url-join@5.0.0: {}
url-join@5.0.0: {}
url-parse@1.5.10:
dependencies:
querystringify: 2.2.0
requires-port: 1.0.0
use-merge-value@1.2.0(react@19.2.3):
use-merge-value@1.2.0(react@19.2.3):
dependencies:
dependencies:
react: 19.2.3
react: 19.2.3
...
@@ -8286,6 +9127,24 @@ snapshots:
...
@@ -8286,6 +9127,24 @@ snapshots:
'@types/unist': 3.0.3
'@types/unist': 3.0.3
vfile-message: 4.0.3
vfile-message: 4.0.3
vite-node@2.1.9(@types/node@20.19.27):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 1.1.2
vite: 5.4.21(@types/node@20.19.27)
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
vite-plugin-checker@0.9.3(eslint@8.57.1)(optionator@0.9.4)(typescript@5.6.3)(vite@5.4.21(@types/node@20.19.27))(vue-tsc@2.2.12(typescript@5.6.3)):
vite-plugin-checker@0.9.3(eslint@8.57.1)(optionator@0.9.4)(typescript@5.6.3)(vite@5.4.21(@types/node@20.19.27))(vue-tsc@2.2.12(typescript@5.6.3)):
dependencies:
dependencies:
'@babel/code-frame': 7.27.1
'@babel/code-frame': 7.27.1
...
@@ -8313,6 +9172,42 @@ snapshots:
...
@@ -8313,6 +9172,42 @@ snapshots:
'@types/node': 20.19.27
'@types/node': 20.19.27
fsevents: 2.3.3
fsevents: 2.3.3
vitest@2.1.9(@types/node@20.19.27)(jsdom@24.1.3):
dependencies:
'@vitest/expect': 2.1.9
'@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@20.19.27))
'@vitest/pretty-format': 2.1.9
'@vitest/runner': 2.1.9
'@vitest/snapshot': 2.1.9
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
chai: 5.3.3
debug: 4.4.3
expect-type: 1.3.0
magic-string: 0.30.21
pathe: 1.1.2
std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.2
tinypool: 1.1.1
tinyrainbow: 1.2.0
vite: 5.4.21(@types/node@20.19.27)
vite-node: 2.1.9(@types/node@20.19.27)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 20.19.27
jsdom: 24.1.3
transitivePeerDependencies:
- less
- lightningcss
- msw
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
vscode-jsonrpc@8.2.0: {}
vscode-jsonrpc@8.2.0: {}
vscode-languageserver-protocol@3.17.5:
vscode-languageserver-protocol@3.17.5:
...
@@ -8337,6 +9232,8 @@ snapshots:
...
@@ -8337,6 +9232,8 @@ snapshots:
chart.js: 4.5.1
chart.js: 4.5.1
vue: 3.5.26(typescript@5.6.3)
vue: 3.5.26(typescript@5.6.3)
vue-component-type-helpers@2.2.12: {}
vue-demi@0.14.10(vue@3.5.26(typescript@5.6.3)):
vue-demi@0.14.10(vue@3.5.26(typescript@5.6.3)):
dependencies:
dependencies:
vue: 3.5.26(typescript@5.6.3)
vue: 3.5.26(typescript@5.6.3)
...
@@ -8382,20 +9279,56 @@ snapshots:
...
@@ -8382,20 +9279,56 @@ snapshots:
optionalDependencies:
optionalDependencies:
typescript: 5.6.3
typescript: 5.6.3
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
web-namespaces@2.0.1: {}
web-namespaces@2.0.1: {}
webidl-conversions@7.0.0: {}
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
whatwg-mimetype@4.0.0: {}
whatwg-url@14.2.0:
dependencies:
tr46: 5.1.1
webidl-conversions: 7.0.0
which@2.0.2:
which@2.0.2:
dependencies:
dependencies:
isexe: 2.0.0
isexe: 2.0.0
why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
wmf@1.0.2: {}
wmf@1.0.2: {}
word-wrap@1.2.5: {}
word-wrap@1.2.5: {}
word@0.3.0: {}
word@0.3.0: {}
wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi@8.1.0:
dependencies:
ansi-styles: 6.2.3
string-width: 5.1.2
strip-ansi: 7.1.2
wrappy@1.0.2: {}
wrappy@1.0.2: {}
ws@8.19.0: {}
xlsx@0.18.5:
xlsx@0.18.5:
dependencies:
dependencies:
adler-32: 1.3.1
adler-32: 1.3.1
...
@@ -8408,6 +9341,10 @@ snapshots:
...
@@ -8408,6 +9341,10 @@ snapshots:
xml-name-validator@4.0.0: {}
xml-name-validator@4.0.0: {}
xml-name-validator@5.0.0: {}
xmlchars@2.2.0: {}
yaml@1.10.2: {}
yaml@1.10.2: {}
yocto-queue@0.1.0: {}
yocto-queue@0.1.0: {}
...
...
frontend/src/App.vue
View file @
dd7f2124
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
import
{
RouterView
,
useRouter
,
useRoute
}
from
'
vue-router
'
import
{
RouterView
,
useRouter
,
useRoute
}
from
'
vue-router
'
import
{
onMounted
,
watch
}
from
'
vue
'
import
{
onMounted
,
watch
}
from
'
vue
'
import
Toast
from
'
@/components/common/Toast.vue
'
import
Toast
from
'
@/components/common/Toast.vue
'
import
NavigationProgress
from
'
@/components/common/NavigationProgress.vue
'
import
{
useAppStore
,
useAuthStore
,
useSubscriptionStore
}
from
'
@/stores
'
import
{
useAppStore
,
useAuthStore
,
useSubscriptionStore
}
from
'
@/stores
'
import
{
getSetupStatus
}
from
'
@/api/setup
'
import
{
getSetupStatus
}
from
'
@/api/setup
'
...
@@ -84,6 +85,7 @@ onMounted(async () => {
...
@@ -84,6 +85,7 @@ onMounted(async () => {
</
script
>
</
script
>
<
template
>
<
template
>
<NavigationProgress
/>
<RouterView
/>
<RouterView
/>
<Toast
/>
<Toast
/>
</
template
>
</
template
>
frontend/src/__tests__/integration/navigation.spec.ts
0 → 100644
View file @
dd7f2124
/**
* 导航集成测试
* 测试完整的页面导航流程、预加载和错误恢复机制
*/
import
{
describe
,
it
,
expect
,
vi
,
beforeEach
,
afterEach
}
from
'
vitest
'
import
{
createRouter
,
createWebHistory
,
type
Router
}
from
'
vue-router
'
import
{
createPinia
,
setActivePinia
}
from
'
pinia
'
import
{
mount
,
flushPromises
}
from
'
@vue/test-utils
'
import
{
defineComponent
,
h
,
nextTick
}
from
'
vue
'
import
{
useNavigationLoadingState
,
_resetNavigationLoadingInstance
}
from
'
@/composables/useNavigationLoading
'
import
{
useRoutePrefetch
}
from
'
@/composables/useRoutePrefetch
'
// Mock 视图组件
const
MockDashboard
=
defineComponent
({
name
:
'
MockDashboard
'
,
render
()
{
return
h
(
'
div
'
,
{
class
:
'
dashboard
'
},
'
Dashboard
'
)
}
})
const
MockKeys
=
defineComponent
({
name
:
'
MockKeys
'
,
render
()
{
return
h
(
'
div
'
,
{
class
:
'
keys
'
},
'
Keys
'
)
}
})
const
MockUsage
=
defineComponent
({
name
:
'
MockUsage
'
,
render
()
{
return
h
(
'
div
'
,
{
class
:
'
usage
'
},
'
Usage
'
)
}
})
// Mock stores
vi
.
mock
(
'
@/stores/auth
'
,
()
=>
({
useAuthStore
:
()
=>
({
isAuthenticated
:
true
,
isAdmin
:
false
,
isSimpleMode
:
false
,
checkAuth
:
vi
.
fn
()
})
}))
vi
.
mock
(
'
@/stores/app
'
,
()
=>
({
useAppStore
:
()
=>
({
siteName
:
'
Test Site
'
})
}))
// 创建测试路由
function
createTestRouter
():
Router
{
return
createRouter
({
history
:
createWebHistory
(),
routes
:
[
{
path
:
'
/
'
,
redirect
:
'
/dashboard
'
},
{
path
:
'
/dashboard
'
,
name
:
'
Dashboard
'
,
component
:
MockDashboard
,
meta
:
{
requiresAuth
:
true
,
title
:
'
Dashboard
'
}
},
{
path
:
'
/keys
'
,
name
:
'
Keys
'
,
component
:
MockKeys
,
meta
:
{
requiresAuth
:
true
,
title
:
'
Keys
'
}
},
{
path
:
'
/usage
'
,
name
:
'
Usage
'
,
component
:
MockUsage
,
meta
:
{
requiresAuth
:
true
,
title
:
'
Usage
'
}
}
]
})
}
// 测试用 App 组件
const
TestApp
=
defineComponent
({
name
:
'
TestApp
'
,
setup
()
{
return
()
=>
h
(
'
div
'
,
{
id
:
'
app
'
},
[
h
(
'
router-view
'
)])
}
})
describe
(
'
Navigation Integration Tests
'
,
()
=>
{
let
router
:
Router
let
originalRequestIdleCallback
:
typeof
window
.
requestIdleCallback
let
originalCancelIdleCallback
:
typeof
window
.
cancelIdleCallback
beforeEach
(()
=>
{
// 设置 Pinia
setActivePinia
(
createPinia
())
// 重置导航加载状态
_resetNavigationLoadingInstance
()
// 创建新的路由实例
router
=
createTestRouter
()
// Mock requestIdleCallback
originalRequestIdleCallback
=
window
.
requestIdleCallback
originalCancelIdleCallback
=
window
.
cancelIdleCallback
vi
.
stubGlobal
(
'
requestIdleCallback
'
,
(
cb
:
IdleRequestCallback
)
=>
{
const
id
=
setTimeout
(()
=>
cb
({
didTimeout
:
false
,
timeRemaining
:
()
=>
50
}),
0
)
return
id
})
vi
.
stubGlobal
(
'
cancelIdleCallback
'
,
(
id
:
number
)
=>
clearTimeout
(
id
))
})
afterEach
(()
=>
{
vi
.
restoreAllMocks
()
window
.
requestIdleCallback
=
originalRequestIdleCallback
window
.
cancelIdleCallback
=
originalCancelIdleCallback
})
describe
(
'
完整页面导航流程
'
,
()
=>
{
it
(
'
导航时应该触发加载状态变化
'
,
async
()
=>
{
const
navigationLoading
=
useNavigationLoadingState
()
// 初始状态
expect
(
navigationLoading
.
isLoading
.
value
).
toBe
(
false
)
// 挂载应用
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
router
]
}
})
// 等待路由初始化
await
router
.
isReady
()
await
flushPromises
()
// 导航到 /dashboard
await
router
.
push
(
'
/dashboard
'
)
await
flushPromises
()
await
nextTick
()
// 导航结束后状态应该重置
expect
(
navigationLoading
.
isLoading
.
value
).
toBe
(
false
)
wrapper
.
unmount
()
})
it
(
'
导航到新页面应该正确渲染组件
'
,
async
()
=>
{
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
router
]
}
})
await
router
.
isReady
()
await
router
.
push
(
'
/dashboard
'
)
await
flushPromises
()
await
nextTick
()
// 检查当前路由
expect
(
router
.
currentRoute
.
value
.
path
).
toBe
(
'
/dashboard
'
)
wrapper
.
unmount
()
})
it
(
'
连续快速导航应该正确处理路由状态
'
,
async
()
=>
{
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
router
]
}
})
await
router
.
isReady
()
await
router
.
push
(
'
/dashboard
'
)
// 快速连续导航
router
.
push
(
'
/keys
'
)
router
.
push
(
'
/usage
'
)
router
.
push
(
'
/dashboard
'
)
await
flushPromises
()
await
nextTick
()
// 应该最终停在 /dashboard
expect
(
router
.
currentRoute
.
value
.
path
).
toBe
(
'
/dashboard
'
)
wrapper
.
unmount
()
})
})
describe
(
'
路由预加载
'
,
()
=>
{
it
(
'
导航后应该触发相关路由预加载
'
,
async
()
=>
{
const
routePrefetch
=
useRoutePrefetch
()
const
triggerSpy
=
vi
.
spyOn
(
routePrefetch
,
'
triggerPrefetch
'
)
// 设置 afterEach 守卫
router
.
afterEach
((
to
)
=>
{
routePrefetch
.
triggerPrefetch
(
to
)
})
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
router
]
}
})
await
router
.
isReady
()
await
router
.
push
(
'
/dashboard
'
)
await
flushPromises
()
// 应该触发预加载
expect
(
triggerSpy
).
toHaveBeenCalled
()
wrapper
.
unmount
()
})
it
(
'
已预加载的路由不应重复预加载
'
,
async
()
=>
{
const
routePrefetch
=
useRoutePrefetch
()
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
router
]
}
})
await
router
.
isReady
()
await
router
.
push
(
'
/dashboard
'
)
await
flushPromises
()
// 手动触发预加载
routePrefetch
.
triggerPrefetch
(
router
.
currentRoute
.
value
)
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
100
))
const
prefetchedCount
=
routePrefetch
.
prefetchedRoutes
.
value
.
size
// 再次触发相同路由预加载
routePrefetch
.
triggerPrefetch
(
router
.
currentRoute
.
value
)
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
100
))
// 预加载数量不应增加
expect
(
routePrefetch
.
prefetchedRoutes
.
value
.
size
).
toBe
(
prefetchedCount
)
wrapper
.
unmount
()
})
it
(
'
路由变化时应取消之前的预加载任务
'
,
async
()
=>
{
const
routePrefetch
=
useRoutePrefetch
()
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
router
]
}
})
await
router
.
isReady
()
// 触发预加载
routePrefetch
.
triggerPrefetch
(
router
.
currentRoute
.
value
)
// 立即导航到新路由(这会在内部调用 cancelPendingPrefetch)
routePrefetch
.
triggerPrefetch
({
path
:
'
/keys
'
}
as
any
)
// 由于 triggerPrefetch 内部调用 cancelPendingPrefetch,检查是否有预加载被正确管理
expect
(
routePrefetch
.
prefetchedRoutes
.
value
.
size
).
toBeLessThanOrEqual
(
2
)
wrapper
.
unmount
()
})
})
describe
(
'
Chunk 加载错误恢复
'
,
()
=>
{
it
(
'
chunk 加载失败应该被正确捕获
'
,
async
()
=>
{
const
errorHandler
=
vi
.
fn
()
// 创建带错误处理的路由
const
errorRouter
=
createRouter
({
history
:
createWebHistory
(),
routes
:
[
{
path
:
'
/dashboard
'
,
name
:
'
Dashboard
'
,
component
:
MockDashboard
},
{
path
:
'
/error-page
'
,
name
:
'
ErrorPage
'
,
// 模拟加载失败的组件
component
:
()
=>
Promise
.
reject
(
new
Error
(
'
Failed to fetch dynamically imported module
'
))
}
]
})
errorRouter
.
onError
(
errorHandler
)
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
errorRouter
]
}
})
await
errorRouter
.
isReady
()
await
errorRouter
.
push
(
'
/dashboard
'
)
await
flushPromises
()
// 尝试导航到会失败的页面
try
{
await
errorRouter
.
push
(
'
/error-page
'
)
}
catch
{
// 预期会失败
}
await
flushPromises
()
// 错误处理器应该被调用
expect
(
errorHandler
).
toHaveBeenCalled
()
wrapper
.
unmount
()
})
it
(
'
chunk 加载错误应该包含正确的错误信息
'
,
async
()
=>
{
let
capturedError
:
Error
|
null
=
null
const
errorRouter
=
createRouter
({
history
:
createWebHistory
(),
routes
:
[
{
path
:
'
/dashboard
'
,
name
:
'
Dashboard
'
,
component
:
MockDashboard
},
{
path
:
'
/chunk-error
'
,
name
:
'
ChunkError
'
,
component
:
()
=>
{
const
error
=
new
Error
(
'
Loading chunk failed
'
)
error
.
name
=
'
ChunkLoadError
'
return
Promise
.
reject
(
error
)
}
}
]
})
errorRouter
.
onError
((
error
)
=>
{
capturedError
=
error
})
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
errorRouter
]
}
})
await
errorRouter
.
isReady
()
try
{
await
errorRouter
.
push
(
'
/chunk-error
'
)
}
catch
{
// 预期会失败
}
await
flushPromises
()
expect
(
capturedError
).
not
.
toBeNull
()
expect
(
capturedError
!
.
name
).
toBe
(
'
ChunkLoadError
'
)
wrapper
.
unmount
()
})
})
describe
(
'
导航状态管理
'
,
()
=>
{
it
(
'
导航开始时 isLoading 应该变为 true
'
,
async
()
=>
{
const
navigationLoading
=
useNavigationLoadingState
()
// 创建一个延迟加载的组件来模拟真实场景
const
DelayedComponent
=
defineComponent
({
name
:
'
DelayedComponent
'
,
async
setup
()
{
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
50
))
return
()
=>
h
(
'
div
'
,
'
Delayed
'
)
}
})
const
delayRouter
=
createRouter
({
history
:
createWebHistory
(),
routes
:
[
{
path
:
'
/dashboard
'
,
name
:
'
Dashboard
'
,
component
:
MockDashboard
},
{
path
:
'
/delayed
'
,
name
:
'
Delayed
'
,
component
:
DelayedComponent
}
]
})
// 设置导航守卫
delayRouter
.
beforeEach
(()
=>
{
navigationLoading
.
startNavigation
()
})
delayRouter
.
afterEach
(()
=>
{
navigationLoading
.
endNavigation
()
})
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
delayRouter
]
}
})
await
delayRouter
.
isReady
()
await
delayRouter
.
push
(
'
/dashboard
'
)
await
flushPromises
()
// 导航结束后 isLoading 应该为 false
expect
(
navigationLoading
.
isLoading
.
value
).
toBe
(
false
)
wrapper
.
unmount
()
})
it
(
'
导航取消时应该正确重置状态
'
,
async
()
=>
{
const
navigationLoading
=
useNavigationLoadingState
()
const
testRouter
=
createRouter
({
history
:
createWebHistory
(),
routes
:
[
{
path
:
'
/dashboard
'
,
name
:
'
Dashboard
'
,
component
:
MockDashboard
},
{
path
:
'
/keys
'
,
name
:
'
Keys
'
,
component
:
MockKeys
,
beforeEnter
:
(
_to
,
_from
,
next
)
=>
{
// 模拟导航取消
next
(
false
)
}
}
]
})
testRouter
.
beforeEach
(()
=>
{
navigationLoading
.
startNavigation
()
})
testRouter
.
afterEach
(()
=>
{
navigationLoading
.
endNavigation
()
})
const
wrapper
=
mount
(
TestApp
,
{
global
:
{
plugins
:
[
testRouter
]
}
})
await
testRouter
.
isReady
()
await
testRouter
.
push
(
'
/dashboard
'
)
await
flushPromises
()
// 尝试导航到被取消的路由
await
testRouter
.
push
(
'
/keys
'
).
catch
(()
=>
{})
await
flushPromises
()
// 导航被取消后,状态应该被重置
// 注意:由于 afterEach 仍然会被调用,isLoading 应该为 false
expect
(
navigationLoading
.
isLoading
.
value
).
toBe
(
false
)
wrapper
.
unmount
()
})
})
})
frontend/src/__tests__/setup.ts
0 → 100644
View file @
dd7f2124
/**
* Vitest 测试环境设置
* 提供全局 mock 和测试工具
*/
import
{
config
}
from
'
@vue/test-utils
'
import
{
vi
}
from
'
vitest
'
// Mock requestIdleCallback (Safari < 15 不支持)
if
(
typeof
globalThis
.
requestIdleCallback
===
'
undefined
'
)
{
globalThis
.
requestIdleCallback
=
((
callback
:
IdleRequestCallback
)
=>
{
return
window
.
setTimeout
(()
=>
callback
({
didTimeout
:
false
,
timeRemaining
:
()
=>
50
}),
1
)
})
as
unknown
as
typeof
requestIdleCallback
}
if
(
typeof
globalThis
.
cancelIdleCallback
===
'
undefined
'
)
{
globalThis
.
cancelIdleCallback
=
((
id
:
number
)
=>
{
window
.
clearTimeout
(
id
)
})
as
unknown
as
typeof
cancelIdleCallback
}
// Mock IntersectionObserver
class
MockIntersectionObserver
{
observe
=
vi
.
fn
()
disconnect
=
vi
.
fn
()
unobserve
=
vi
.
fn
()
}
globalThis
.
IntersectionObserver
=
MockIntersectionObserver
as
unknown
as
typeof
IntersectionObserver
// Mock ResizeObserver
class
MockResizeObserver
{
observe
=
vi
.
fn
()
disconnect
=
vi
.
fn
()
unobserve
=
vi
.
fn
()
}
globalThis
.
ResizeObserver
=
MockResizeObserver
as
unknown
as
typeof
ResizeObserver
// Vue Test Utils 全局配置
config
.
global
.
stubs
=
{
// 可以在这里添加全局 stub
}
// 设置全局测试超时
vi
.
setConfig
({
testTimeout
:
10000
})
frontend/src/components/account/AccountCapacityCell.vue
0 → 100644
View file @
dd7f2124
<
template
>
<div
class=
"flex flex-col gap-1.5"
>
<!-- 并发槽位 -->
<div
class=
"flex items-center gap-1.5"
>
<span
:class=
"[
'inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium',
concurrencyClass
]"
>
<svg
class=
"h-3 w-3"
fill=
"none"
viewBox=
"0 0 24 24"
stroke=
"currentColor"
stroke-width=
"2"
>
<path
stroke-linecap=
"round"
stroke-linejoin=
"round"
d=
"M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"
/>
</svg>
<span
class=
"font-mono"
>
{{
currentConcurrency
}}
</span>
<span
class=
"text-gray-400 dark:text-gray-500"
>
/
</span>
<span
class=
"font-mono"
>
{{
account
.
concurrency
}}
</span>
</span>
</div>
<!-- 5h窗口费用限制(仅 Anthropic OAuth/SetupToken 且启用时显示) -->
<div
v-if=
"showWindowCost"
class=
"flex items-center gap-1"
>
<span
:class=
"[
'inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[10px] font-medium',
windowCostClass
]"
:title=
"windowCostTooltip"
>
<svg
class=
"h-2.5 w-2.5"
fill=
"none"
viewBox=
"0 0 24 24"
stroke=
"currentColor"
stroke-width=
"2"
>
<path
stroke-linecap=
"round"
stroke-linejoin=
"round"
d=
"M12 6v12m-3-2.818l.879.659c1.171.879 3.07.879 4.242 0 1.172-.879 1.172-2.303 0-3.182C13.536 12.219 12.768 12 12 12c-.725 0-1.45-.22-2.003-.659-1.106-.879-1.106-2.303 0-3.182s2.9-.879 4.006 0l.415.33M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span
class=
"font-mono"
>
$
{{
formatCost
(
currentWindowCost
)
}}
</span>
<span
class=
"text-gray-400 dark:text-gray-500"
>
/
</span>
<span
class=
"font-mono"
>
$
{{
formatCost
(
account
.
window_cost_limit
)
}}
</span>
</span>
</div>
<!-- 会话数量限制(仅 Anthropic OAuth/SetupToken 且启用时显示) -->
<div
v-if=
"showSessionLimit"
class=
"flex items-center gap-1"
>
<span
:class=
"[
'inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[10px] font-medium',
sessionLimitClass
]"
:title=
"sessionLimitTooltip"
>
<svg
class=
"h-2.5 w-2.5"
fill=
"none"
viewBox=
"0 0 24 24"
stroke=
"currentColor"
stroke-width=
"2"
>
<path
stroke-linecap=
"round"
stroke-linejoin=
"round"
d=
"M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"
/>
</svg>
<span
class=
"font-mono"
>
{{
activeSessions
}}
</span>
<span
class=
"text-gray-400 dark:text-gray-500"
>
/
</span>
<span
class=
"font-mono"
>
{{
account
.
max_sessions
}}
</span>
</span>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
computed
}
from
'
vue
'
import
{
useI18n
}
from
'
vue-i18n
'
import
type
{
Account
}
from
'
@/types
'
const
props
=
defineProps
<
{
account
:
Account
}
>
()
const
{
t
}
=
useI18n
()
// 当前并发数
const
currentConcurrency
=
computed
(()
=>
props
.
account
.
current_concurrency
||
0
)
// 是否为 Anthropic OAuth/SetupToken 账号
const
isAnthropicOAuthOrSetupToken
=
computed
(()
=>
{
return
(
props
.
account
.
platform
===
'
anthropic
'
&&
(
props
.
account
.
type
===
'
oauth
'
||
props
.
account
.
type
===
'
setup-token
'
)
)
})
// 是否显示窗口费用限制
const
showWindowCost
=
computed
(()
=>
{
return
(
isAnthropicOAuthOrSetupToken
.
value
&&
props
.
account
.
window_cost_limit
!==
undefined
&&
props
.
account
.
window_cost_limit
!==
null
&&
props
.
account
.
window_cost_limit
>
0
)
})
// 当前窗口费用
const
currentWindowCost
=
computed
(()
=>
props
.
account
.
current_window_cost
??
0
)
// 是否显示会话限制
const
showSessionLimit
=
computed
(()
=>
{
return
(
isAnthropicOAuthOrSetupToken
.
value
&&
props
.
account
.
max_sessions
!==
undefined
&&
props
.
account
.
max_sessions
!==
null
&&
props
.
account
.
max_sessions
>
0
)
})
// 当前活跃会话数
const
activeSessions
=
computed
(()
=>
props
.
account
.
active_sessions
??
0
)
// 并发状态样式
const
concurrencyClass
=
computed
(()
=>
{
const
current
=
currentConcurrency
.
value
const
max
=
props
.
account
.
concurrency
if
(
current
>=
max
)
{
return
'
bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400
'
}
if
(
current
>
0
)
{
return
'
bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400
'
}
return
'
bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400
'
})
// 窗口费用状态样式
const
windowCostClass
=
computed
(()
=>
{
if
(
!
showWindowCost
.
value
)
return
''
const
current
=
currentWindowCost
.
value
const
limit
=
props
.
account
.
window_cost_limit
||
0
const
reserve
=
props
.
account
.
window_cost_sticky_reserve
||
10
// >= 阈值+预留: 完全不可调度 (红色)
if
(
current
>=
limit
+
reserve
)
{
return
'
bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400
'
}
// >= 阈值: 仅粘性会话 (橙色)
if
(
current
>=
limit
)
{
return
'
bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400
'
}
// >= 80% 阈值: 警告 (黄色)
if
(
current
>=
limit
*
0.8
)
{
return
'
bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400
'
}
// 正常 (绿色)
return
'
bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400
'
})
// 窗口费用提示文字
const
windowCostTooltip
=
computed
(()
=>
{
if
(
!
showWindowCost
.
value
)
return
''
const
current
=
currentWindowCost
.
value
const
limit
=
props
.
account
.
window_cost_limit
||
0
const
reserve
=
props
.
account
.
window_cost_sticky_reserve
||
10
if
(
current
>=
limit
+
reserve
)
{
return
t
(
'
admin.accounts.capacity.windowCost.blocked
'
)
}
if
(
current
>=
limit
)
{
return
t
(
'
admin.accounts.capacity.windowCost.stickyOnly
'
)
}
return
t
(
'
admin.accounts.capacity.windowCost.normal
'
)
})
// 会话限制状态样式
const
sessionLimitClass
=
computed
(()
=>
{
if
(
!
showSessionLimit
.
value
)
return
''
const
current
=
activeSessions
.
value
const
max
=
props
.
account
.
max_sessions
||
0
// >= 最大: 完全占满 (红色)
if
(
current
>=
max
)
{
return
'
bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400
'
}
// >= 80%: 警告 (黄色)
if
(
current
>=
max
*
0.8
)
{
return
'
bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400
'
}
// 正常 (绿色)
return
'
bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400
'
})
// 会话限制提示文字
const
sessionLimitTooltip
=
computed
(()
=>
{
if
(
!
showSessionLimit
.
value
)
return
''
const
current
=
activeSessions
.
value
const
max
=
props
.
account
.
max_sessions
||
0
const
idle
=
props
.
account
.
session_idle_timeout_minutes
||
5
if
(
current
>=
max
)
{
return
t
(
'
admin.accounts.capacity.sessions.full
'
,
{
idle
})
}
return
t
(
'
admin.accounts.capacity.sessions.normal
'
,
{
idle
})
})
// 格式化费用显示
const
formatCost
=
(
value
:
number
|
null
|
undefined
)
=>
{
if
(
value
===
null
||
value
===
undefined
)
return
'
0
'
return
value
.
toFixed
(
2
)
}
</
script
>
frontend/src/components/account/EditAccountModal.vue
View file @
dd7f2124
...
@@ -604,6 +604,136 @@
...
@@ -604,6 +604,136 @@
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<!--
Quota
Control
Section
(
Anthropic
OAuth
/
SetupToken
only
)
-->
<
div
v
-
if
=
"
account?.platform === 'anthropic' && (account?.type === 'oauth' || account?.type === 'setup-token')
"
class
=
"
border-t border-gray-200 pt-4 dark:border-dark-600 space-y-4
"
>
<
div
class
=
"
mb-3
"
>
<
h3
class
=
"
input-label mb-0 text-base font-semibold
"
>
{{
t
(
'
admin.accounts.quotaControl.title
'
)
}}
<
/h3
>
<
p
class
=
"
mt-1 text-xs text-gray-500 dark:text-gray-400
"
>
{{
t
(
'
admin.accounts.quotaControl.hint
'
)
}}
<
/p
>
<
/div
>
<!--
Window
Cost
Limit
-->
<
div
class
=
"
rounded-lg border border-gray-200 p-4 dark:border-dark-600
"
>
<
div
class
=
"
mb-3 flex items-center justify-between
"
>
<
div
>
<
label
class
=
"
input-label mb-0
"
>
{{
t
(
'
admin.accounts.quotaControl.windowCost.label
'
)
}}
<
/label
>
<
p
class
=
"
mt-1 text-xs text-gray-500 dark:text-gray-400
"
>
{{
t
(
'
admin.accounts.quotaControl.windowCost.hint
'
)
}}
<
/p
>
<
/div
>
<
button
type
=
"
button
"
@
click
=
"
windowCostEnabled = !windowCostEnabled
"
:
class
=
"
[
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2',
windowCostEnabled ? 'bg-primary-600' : 'bg-gray-200 dark:bg-dark-600'
]
"
>
<
span
:
class
=
"
[
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',
windowCostEnabled ? 'translate-x-5' : 'translate-x-0'
]
"
/>
<
/button
>
<
/div
>
<
div
v
-
if
=
"
windowCostEnabled
"
class
=
"
grid grid-cols-2 gap-4
"
>
<
div
>
<
label
class
=
"
input-label
"
>
{{
t
(
'
admin.accounts.quotaControl.windowCost.limit
'
)
}}
<
/label
>
<
div
class
=
"
relative
"
>
<
span
class
=
"
absolute left-3 top-1/2 -translate-y-1/2 text-gray-500 dark:text-gray-400
"
>
$
<
/span
>
<
input
v
-
model
.
number
=
"
windowCostLimit
"
type
=
"
number
"
min
=
"
0
"
step
=
"
1
"
class
=
"
input pl-7
"
:
placeholder
=
"
t('admin.accounts.quotaControl.windowCost.limitPlaceholder')
"
/>
<
/div
>
<
p
class
=
"
input-hint
"
>
{{
t
(
'
admin.accounts.quotaControl.windowCost.limitHint
'
)
}}
<
/p
>
<
/div
>
<
div
>
<
label
class
=
"
input-label
"
>
{{
t
(
'
admin.accounts.quotaControl.windowCost.stickyReserve
'
)
}}
<
/label
>
<
div
class
=
"
relative
"
>
<
span
class
=
"
absolute left-3 top-1/2 -translate-y-1/2 text-gray-500 dark:text-gray-400
"
>
$
<
/span
>
<
input
v
-
model
.
number
=
"
windowCostStickyReserve
"
type
=
"
number
"
min
=
"
0
"
step
=
"
1
"
class
=
"
input pl-7
"
:
placeholder
=
"
t('admin.accounts.quotaControl.windowCost.stickyReservePlaceholder')
"
/>
<
/div
>
<
p
class
=
"
input-hint
"
>
{{
t
(
'
admin.accounts.quotaControl.windowCost.stickyReserveHint
'
)
}}
<
/p
>
<
/div
>
<
/div
>
<
/div
>
<!--
Session
Limit
-->
<
div
class
=
"
rounded-lg border border-gray-200 p-4 dark:border-dark-600
"
>
<
div
class
=
"
mb-3 flex items-center justify-between
"
>
<
div
>
<
label
class
=
"
input-label mb-0
"
>
{{
t
(
'
admin.accounts.quotaControl.sessionLimit.label
'
)
}}
<
/label
>
<
p
class
=
"
mt-1 text-xs text-gray-500 dark:text-gray-400
"
>
{{
t
(
'
admin.accounts.quotaControl.sessionLimit.hint
'
)
}}
<
/p
>
<
/div
>
<
button
type
=
"
button
"
@
click
=
"
sessionLimitEnabled = !sessionLimitEnabled
"
:
class
=
"
[
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2',
sessionLimitEnabled ? 'bg-primary-600' : 'bg-gray-200 dark:bg-dark-600'
]
"
>
<
span
:
class
=
"
[
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',
sessionLimitEnabled ? 'translate-x-5' : 'translate-x-0'
]
"
/>
<
/button
>
<
/div
>
<
div
v
-
if
=
"
sessionLimitEnabled
"
class
=
"
grid grid-cols-2 gap-4
"
>
<
div
>
<
label
class
=
"
input-label
"
>
{{
t
(
'
admin.accounts.quotaControl.sessionLimit.maxSessions
'
)
}}
<
/label
>
<
input
v
-
model
.
number
=
"
maxSessions
"
type
=
"
number
"
min
=
"
1
"
step
=
"
1
"
class
=
"
input
"
:
placeholder
=
"
t('admin.accounts.quotaControl.sessionLimit.maxSessionsPlaceholder')
"
/>
<
p
class
=
"
input-hint
"
>
{{
t
(
'
admin.accounts.quotaControl.sessionLimit.maxSessionsHint
'
)
}}
<
/p
>
<
/div
>
<
div
>
<
label
class
=
"
input-label
"
>
{{
t
(
'
admin.accounts.quotaControl.sessionLimit.idleTimeout
'
)
}}
<
/label
>
<
div
class
=
"
relative
"
>
<
input
v
-
model
.
number
=
"
sessionIdleTimeout
"
type
=
"
number
"
min
=
"
1
"
step
=
"
1
"
class
=
"
input pr-12
"
:
placeholder
=
"
t('admin.accounts.quotaControl.sessionLimit.idleTimeoutPlaceholder')
"
/>
<
span
class
=
"
absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 dark:text-gray-400
"
>
{{
t
(
'
common.minutes
'
)
}}
<
/span
>
<
/div
>
<
p
class
=
"
input-hint
"
>
{{
t
(
'
admin.accounts.quotaControl.sessionLimit.idleTimeoutHint
'
)
}}
<
/p
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"
border-t border-gray-200 pt-4 dark:border-dark-600
"
>
<
div
class
=
"
border-t border-gray-200 pt-4 dark:border-dark-600
"
>
<
div
>
<
div
>
<
label
class
=
"
input-label
"
>
{{
t
(
'
common.status
'
)
}}
<
/label
>
<
label
class
=
"
input-label
"
>
{{
t
(
'
common.status
'
)
}}
<
/label
>
...
@@ -767,6 +897,14 @@ const mixedScheduling = ref(false) // For antigravity accounts: enable mixed sch
...
@@ -767,6 +897,14 @@ const mixedScheduling = ref(false) // For antigravity accounts: enable mixed sch
const
tempUnschedEnabled
=
ref
(
false
)
const
tempUnschedEnabled
=
ref
(
false
)
const
tempUnschedRules
=
ref
<
TempUnschedRuleForm
[]
>
([])
const
tempUnschedRules
=
ref
<
TempUnschedRuleForm
[]
>
([])
// Quota control state (Anthropic OAuth/SetupToken only)
const
windowCostEnabled
=
ref
(
false
)
const
windowCostLimit
=
ref
<
number
|
null
>
(
null
)
const
windowCostStickyReserve
=
ref
<
number
|
null
>
(
null
)
const
sessionLimitEnabled
=
ref
(
false
)
const
maxSessions
=
ref
<
number
|
null
>
(
null
)
const
sessionIdleTimeout
=
ref
<
number
|
null
>
(
null
)
// Computed: current preset mappings based on platform
// Computed: current preset mappings based on platform
const
presetMappings
=
computed
(()
=>
getPresetMappingsByPlatform
(
props
.
account
?.
platform
||
'
anthropic
'
))
const
presetMappings
=
computed
(()
=>
getPresetMappingsByPlatform
(
props
.
account
?.
platform
||
'
anthropic
'
))
const
tempUnschedPresets
=
computed
(()
=>
[
const
tempUnschedPresets
=
computed
(()
=>
[
...
@@ -854,6 +992,9 @@ watch(
...
@@ -854,6 +992,9 @@ watch(
const
extra
=
newAccount
.
extra
as
Record
<
string
,
unknown
>
|
undefined
const
extra
=
newAccount
.
extra
as
Record
<
string
,
unknown
>
|
undefined
mixedScheduling
.
value
=
extra
?.
mixed_scheduling
===
true
mixedScheduling
.
value
=
extra
?.
mixed_scheduling
===
true
// Load quota control settings (Anthropic OAuth/SetupToken only)
loadQuotaControlSettings
(
newAccount
)
loadTempUnschedRules
(
credentials
)
loadTempUnschedRules
(
credentials
)
// Initialize API Key fields for apikey type
// Initialize API Key fields for apikey type
...
@@ -1087,6 +1228,35 @@ function loadTempUnschedRules(credentials?: Record<string, unknown>) {
...
@@ -1087,6 +1228,35 @@ function loadTempUnschedRules(credentials?: Record<string, unknown>) {
}
)
}
)
}
}
// Load quota control settings from account (Anthropic OAuth/SetupToken only)
function
loadQuotaControlSettings
(
account
:
Account
)
{
// Reset all quota control state first
windowCostEnabled
.
value
=
false
windowCostLimit
.
value
=
null
windowCostStickyReserve
.
value
=
null
sessionLimitEnabled
.
value
=
false
maxSessions
.
value
=
null
sessionIdleTimeout
.
value
=
null
// Only applies to Anthropic OAuth/SetupToken accounts
if
(
account
.
platform
!==
'
anthropic
'
||
(
account
.
type
!==
'
oauth
'
&&
account
.
type
!==
'
setup-token
'
))
{
return
}
// Load from extra field (via backend DTO fields)
if
(
account
.
window_cost_limit
!=
null
&&
account
.
window_cost_limit
>
0
)
{
windowCostEnabled
.
value
=
true
windowCostLimit
.
value
=
account
.
window_cost_limit
windowCostStickyReserve
.
value
=
account
.
window_cost_sticky_reserve
??
10
}
if
(
account
.
max_sessions
!=
null
&&
account
.
max_sessions
>
0
)
{
sessionLimitEnabled
.
value
=
true
maxSessions
.
value
=
account
.
max_sessions
sessionIdleTimeout
.
value
=
account
.
session_idle_timeout_minutes
??
5
}
}
function
formatTempUnschedKeywords
(
value
:
unknown
)
{
function
formatTempUnschedKeywords
(
value
:
unknown
)
{
if
(
Array
.
isArray
(
value
))
{
if
(
Array
.
isArray
(
value
))
{
return
value
return
value
...
@@ -1214,6 +1384,32 @@ const handleSubmit = async () => {
...
@@ -1214,6 +1384,32 @@ const handleSubmit = async () => {
updatePayload
.
extra
=
newExtra
updatePayload
.
extra
=
newExtra
}
}
// For Anthropic OAuth/SetupToken accounts, handle quota control settings in extra
if
(
props
.
account
.
platform
===
'
anthropic
'
&&
(
props
.
account
.
type
===
'
oauth
'
||
props
.
account
.
type
===
'
setup-token
'
))
{
const
currentExtra
=
(
props
.
account
.
extra
as
Record
<
string
,
unknown
>
)
||
{
}
const
newExtra
:
Record
<
string
,
unknown
>
=
{
...
currentExtra
}
// Window cost limit settings
if
(
windowCostEnabled
.
value
&&
windowCostLimit
.
value
!=
null
&&
windowCostLimit
.
value
>
0
)
{
newExtra
.
window_cost_limit
=
windowCostLimit
.
value
newExtra
.
window_cost_sticky_reserve
=
windowCostStickyReserve
.
value
??
10
}
else
{
delete
newExtra
.
window_cost_limit
delete
newExtra
.
window_cost_sticky_reserve
}
// Session limit settings
if
(
sessionLimitEnabled
.
value
&&
maxSessions
.
value
!=
null
&&
maxSessions
.
value
>
0
)
{
newExtra
.
max_sessions
=
maxSessions
.
value
newExtra
.
session_idle_timeout_minutes
=
sessionIdleTimeout
.
value
??
5
}
else
{
delete
newExtra
.
max_sessions
delete
newExtra
.
session_idle_timeout_minutes
}
updatePayload
.
extra
=
newExtra
}
await
adminAPI
.
accounts
.
update
(
props
.
account
.
id
,
updatePayload
)
await
adminAPI
.
accounts
.
update
(
props
.
account
.
id
,
updatePayload
)
appStore
.
showSuccess
(
t
(
'
admin.accounts.accountUpdated
'
))
appStore
.
showSuccess
(
t
(
'
admin.accounts.accountUpdated
'
))
emit
(
'
updated
'
)
emit
(
'
updated
'
)
...
...
frontend/src/components/common/NavigationProgress.vue
0 → 100644
View file @
dd7f2124
<
script
setup
lang=
"ts"
>
/**
* 导航进度条组件
* 在页面顶部显示加载进度,提供导航反馈
*/
import
{
computed
}
from
'
vue
'
import
{
useNavigationLoadingState
}
from
'
@/composables/useNavigationLoading
'
const
{
isLoading
}
=
useNavigationLoadingState
()
// 进度条可见性
const
isVisible
=
computed
(()
=>
isLoading
.
value
)
</
script
>
<
template
>
<Transition
name=
"progress-fade"
>
<div
v-show=
"isVisible"
class=
"navigation-progress"
role=
"progressbar"
aria-label=
"Loading"
aria-valuenow=
"0"
aria-valuemin=
"0"
aria-valuemax=
"100"
>
<div
class=
"navigation-progress-bar"
/>
</div>
</Transition>
</
template
>
<
style
scoped
>
.navigation-progress
{
position
:
fixed
;
top
:
0
;
left
:
0
;
right
:
0
;
height
:
3px
;
z-index
:
9999
;
overflow
:
hidden
;
background
:
transparent
;
}
.navigation-progress-bar
{
height
:
100%
;
width
:
100%
;
background
:
linear-gradient
(
90deg
,
transparent
0%
,
theme
(
'colors.primary.400'
)
20%
,
theme
(
'colors.primary.500'
)
50%
,
theme
(
'colors.primary.400'
)
80%
,
transparent
100%
);
animation
:
progress-slide
1.5s
ease-in-out
infinite
;
}
/* 暗色模式下的进度条颜色 */
:root
.dark
.navigation-progress-bar
{
background
:
linear-gradient
(
90deg
,
transparent
0%
,
theme
(
'colors.primary.500'
)
20%
,
theme
(
'colors.primary.400'
)
50%
,
theme
(
'colors.primary.500'
)
80%
,
transparent
100%
);
}
/* 进度条滑动动画 */
@keyframes
progress-slide
{
0
%
{
transform
:
translateX
(
-100%
);
}
100
%
{
transform
:
translateX
(
100%
);
}
}
/* 淡入淡出过渡 */
.progress-fade-enter-active
{
transition
:
opacity
0.15s
ease-out
;
}
.progress-fade-leave-active
{
transition
:
opacity
0.3s
ease-out
;
}
.progress-fade-enter-from
,
.progress-fade-leave-to
{
opacity
:
0
;
}
/* 减少动画模式 */
@media
(
prefers-reduced-motion
:
reduce
)
{
.navigation-progress-bar
{
animation
:
progress-pulse
2s
ease-in-out
infinite
;
}
@keyframes
progress-pulse
{
0
%,
100
%
{
opacity
:
0.4
;
}
50
%
{
opacity
:
1
;
}
}
}
</
style
>
frontend/src/components/common/__tests__/NavigationProgress.spec.ts
0 → 100644
View file @
dd7f2124
/**
* NavigationProgress 组件单元测试
*/
import
{
describe
,
it
,
expect
,
vi
,
beforeEach
}
from
'
vitest
'
import
{
mount
}
from
'
@vue/test-utils
'
import
{
ref
}
from
'
vue
'
import
NavigationProgress
from
'
../../common/NavigationProgress.vue
'
// Mock useNavigationLoadingState
const
mockIsLoading
=
ref
(
false
)
vi
.
mock
(
'
@/composables/useNavigationLoading
'
,
()
=>
({
useNavigationLoadingState
:
()
=>
({
isLoading
:
mockIsLoading
})
}))
describe
(
'
NavigationProgress
'
,
()
=>
{
beforeEach
(()
=>
{
mockIsLoading
.
value
=
false
})
it
(
'
isLoading=false 时进度条应该隐藏
'
,
()
=>
{
mockIsLoading
.
value
=
false
const
wrapper
=
mount
(
NavigationProgress
)
const
progressBar
=
wrapper
.
find
(
'
.navigation-progress
'
)
// v-show 会设置 display: none
expect
(
progressBar
.
isVisible
()).
toBe
(
false
)
})
it
(
'
isLoading=true 时进度条应该可见
'
,
async
()
=>
{
mockIsLoading
.
value
=
true
const
wrapper
=
mount
(
NavigationProgress
)
await
wrapper
.
vm
.
$nextTick
()
const
progressBar
=
wrapper
.
find
(
'
.navigation-progress
'
)
expect
(
progressBar
.
exists
()).
toBe
(
true
)
expect
(
progressBar
.
isVisible
()).
toBe
(
true
)
})
it
(
'
应该有正确的 ARIA 属性
'
,
()
=>
{
mockIsLoading
.
value
=
true
const
wrapper
=
mount
(
NavigationProgress
)
const
progressBar
=
wrapper
.
find
(
'
.navigation-progress
'
)
expect
(
progressBar
.
attributes
(
'
role
'
)).
toBe
(
'
progressbar
'
)
expect
(
progressBar
.
attributes
(
'
aria-label
'
)).
toBe
(
'
Loading
'
)
expect
(
progressBar
.
attributes
(
'
aria-valuemin
'
)).
toBe
(
'
0
'
)
expect
(
progressBar
.
attributes
(
'
aria-valuemax
'
)).
toBe
(
'
100
'
)
})
it
(
'
进度条应该有动画 class
'
,
()
=>
{
mockIsLoading
.
value
=
true
const
wrapper
=
mount
(
NavigationProgress
)
const
bar
=
wrapper
.
find
(
'
.navigation-progress-bar
'
)
expect
(
bar
.
exists
()).
toBe
(
true
)
})
it
(
'
应该正确响应 isLoading 状态变化
'
,
async
()
=>
{
// 测试初始状态为 false
mockIsLoading
.
value
=
false
const
wrapper
=
mount
(
NavigationProgress
)
await
wrapper
.
vm
.
$nextTick
()
// 初始状态隐藏
expect
(
wrapper
.
find
(
'
.navigation-progress
'
).
isVisible
()).
toBe
(
false
)
// 卸载后重新挂载以测试 true 状态
wrapper
.
unmount
()
// 改变为 true 后重新挂载
mockIsLoading
.
value
=
true
const
wrapper2
=
mount
(
NavigationProgress
)
await
wrapper2
.
vm
.
$nextTick
()
expect
(
wrapper2
.
find
(
'
.navigation-progress
'
).
isVisible
()).
toBe
(
true
)
// 清理
wrapper2
.
unmount
()
})
})
frontend/src/composables/__tests__/useNavigationLoading.spec.ts
0 → 100644
View file @
dd7f2124
/**
* useNavigationLoading 组合式函数单元测试
*/
import
{
describe
,
it
,
expect
,
vi
,
beforeEach
,
afterEach
}
from
'
vitest
'
import
{
useNavigationLoading
,
_resetNavigationLoadingInstance
}
from
'
../useNavigationLoading
'
describe
(
'
useNavigationLoading
'
,
()
=>
{
beforeEach
(()
=>
{
vi
.
useFakeTimers
()
_resetNavigationLoadingInstance
()
})
afterEach
(()
=>
{
vi
.
useRealTimers
()
})
describe
(
'
startNavigation
'
,
()
=>
{
it
(
'
导航开始时 isNavigating 应变为 true
'
,
()
=>
{
const
{
isNavigating
,
startNavigation
}
=
useNavigationLoading
()
expect
(
isNavigating
.
value
).
toBe
(
false
)
startNavigation
()
expect
(
isNavigating
.
value
).
toBe
(
true
)
})
it
(
'
导航开始后延迟显示加载指示器(防闪烁)
'
,
()
=>
{
const
{
isLoading
,
startNavigation
,
ANTI_FLICKER_DELAY
}
=
useNavigationLoading
()
startNavigation
()
// 立即检查,不应该显示
expect
(
isLoading
.
value
).
toBe
(
false
)
// 经过防闪烁延迟后应该显示
vi
.
advanceTimersByTime
(
ANTI_FLICKER_DELAY
)
expect
(
isLoading
.
value
).
toBe
(
true
)
})
})
describe
(
'
endNavigation
'
,
()
=>
{
it
(
'
导航结束时 isLoading 应变为 false
'
,
()
=>
{
const
{
isLoading
,
startNavigation
,
endNavigation
,
ANTI_FLICKER_DELAY
}
=
useNavigationLoading
()
startNavigation
()
vi
.
advanceTimersByTime
(
ANTI_FLICKER_DELAY
)
expect
(
isLoading
.
value
).
toBe
(
true
)
endNavigation
()
expect
(
isLoading
.
value
).
toBe
(
false
)
})
it
(
'
导航结束时 isNavigating 应变为 false
'
,
()
=>
{
const
{
isNavigating
,
startNavigation
,
endNavigation
}
=
useNavigationLoading
()
startNavigation
()
expect
(
isNavigating
.
value
).
toBe
(
true
)
endNavigation
()
expect
(
isNavigating
.
value
).
toBe
(
false
)
})
})
describe
(
'
快速导航(< 100ms)防闪烁
'
,
()
=>
{
it
(
'
快速导航不应触发显示加载指示器
'
,
()
=>
{
const
{
isLoading
,
startNavigation
,
endNavigation
,
ANTI_FLICKER_DELAY
}
=
useNavigationLoading
()
startNavigation
()
// 在防闪烁延迟之前结束导航
vi
.
advanceTimersByTime
(
ANTI_FLICKER_DELAY
-
50
)
endNavigation
()
// 不应该显示加载指示器
expect
(
isLoading
.
value
).
toBe
(
false
)
// 即使继续等待也不应该显示
vi
.
advanceTimersByTime
(
100
)
expect
(
isLoading
.
value
).
toBe
(
false
)
})
})
describe
(
'
cancelNavigation
'
,
()
=>
{
it
(
'
导航取消时应正确重置状态
'
,
()
=>
{
const
{
isLoading
,
startNavigation
,
cancelNavigation
,
ANTI_FLICKER_DELAY
}
=
useNavigationLoading
()
startNavigation
()
vi
.
advanceTimersByTime
(
ANTI_FLICKER_DELAY
/
2
)
cancelNavigation
()
// 取消后不应该触发显示
vi
.
advanceTimersByTime
(
ANTI_FLICKER_DELAY
)
expect
(
isLoading
.
value
).
toBe
(
false
)
})
})
describe
(
'
getNavigationDuration
'
,
()
=>
{
it
(
'
应该返回正确的导航持续时间
'
,
()
=>
{
const
{
startNavigation
,
getNavigationDuration
}
=
useNavigationLoading
()
expect
(
getNavigationDuration
()).
toBeNull
()
startNavigation
()
vi
.
advanceTimersByTime
(
500
)
const
duration
=
getNavigationDuration
()
expect
(
duration
).
toBe
(
500
)
})
it
(
'
导航结束后应返回 null
'
,
()
=>
{
const
{
startNavigation
,
endNavigation
,
getNavigationDuration
}
=
useNavigationLoading
()
startNavigation
()
vi
.
advanceTimersByTime
(
500
)
endNavigation
()
expect
(
getNavigationDuration
()).
toBeNull
()
})
})
describe
(
'
resetState
'
,
()
=>
{
it
(
'
应该重置所有状态
'
,
()
=>
{
const
{
isLoading
,
isNavigating
,
startNavigation
,
resetState
,
ANTI_FLICKER_DELAY
}
=
useNavigationLoading
()
startNavigation
()
vi
.
advanceTimersByTime
(
ANTI_FLICKER_DELAY
)
expect
(
isLoading
.
value
).
toBe
(
true
)
expect
(
isNavigating
.
value
).
toBe
(
true
)
resetState
()
expect
(
isLoading
.
value
).
toBe
(
false
)
expect
(
isNavigating
.
value
).
toBe
(
false
)
})
})
describe
(
'
连续导航场景
'
,
()
=>
{
it
(
'
连续快速导航应正确处理状态
'
,
()
=>
{
const
{
isLoading
,
startNavigation
,
cancelNavigation
,
endNavigation
,
ANTI_FLICKER_DELAY
}
=
useNavigationLoading
()
// 第一次导航
startNavigation
()
vi
.
advanceTimersByTime
(
30
)
// 第二次导航(取消第一次)
cancelNavigation
()
startNavigation
()
vi
.
advanceTimersByTime
(
30
)
// 第三次导航(取消第二次)
cancelNavigation
()
startNavigation
()
// 这次等待足够长时间
vi
.
advanceTimersByTime
(
ANTI_FLICKER_DELAY
)
expect
(
isLoading
.
value
).
toBe
(
true
)
// 结束导航
endNavigation
()
expect
(
isLoading
.
value
).
toBe
(
false
)
})
})
describe
(
'
ANTI_FLICKER_DELAY 常量
'
,
()
=>
{
it
(
'
应该为 100ms
'
,
()
=>
{
const
{
ANTI_FLICKER_DELAY
}
=
useNavigationLoading
()
expect
(
ANTI_FLICKER_DELAY
).
toBe
(
100
)
})
})
})
frontend/src/composables/__tests__/useRoutePrefetch.spec.ts
0 → 100644
View file @
dd7f2124
/**
* useRoutePrefetch 组合式函数单元测试
*/
import
{
describe
,
it
,
expect
,
vi
,
beforeEach
,
afterEach
}
from
'
vitest
'
import
type
{
RouteLocationNormalized
,
Router
,
RouteRecordNormalized
}
from
'
vue-router
'
import
{
useRoutePrefetch
,
_adminPrefetchMap
,
_userPrefetchMap
}
from
'
../useRoutePrefetch
'
// Mock 路由对象
const
createMockRoute
=
(
path
:
string
):
RouteLocationNormalized
=>
({
path
,
name
:
undefined
,
params
:
{},
query
:
{},
hash
:
''
,
fullPath
:
path
,
matched
:
[],
meta
:
{},
redirectedFrom
:
undefined
})
// Mock Router
const
createMockRouter
=
():
Router
=>
{
const
mockImportFn
=
vi
.
fn
().
mockResolvedValue
({
default
:
{}
})
const
routes
:
Partial
<
RouteRecordNormalized
>
[]
=
[
{
path
:
'
/admin/dashboard
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/admin/accounts
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/admin/users
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/admin/groups
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/admin/subscriptions
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/admin/redeem
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/dashboard
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/keys
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/usage
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/redeem
'
,
components
:
{
default
:
mockImportFn
}
},
{
path
:
'
/profile
'
,
components
:
{
default
:
mockImportFn
}
}
]
return
{
getRoutes
:
()
=>
routes
as
RouteRecordNormalized
[]
}
as
Router
}
describe
(
'
useRoutePrefetch
'
,
()
=>
{
let
originalRequestIdleCallback
:
typeof
window
.
requestIdleCallback
let
originalCancelIdleCallback
:
typeof
window
.
cancelIdleCallback
let
mockRouter
:
Router
beforeEach
(()
=>
{
mockRouter
=
createMockRouter
()
// 保存原始函数
originalRequestIdleCallback
=
window
.
requestIdleCallback
originalCancelIdleCallback
=
window
.
cancelIdleCallback
// Mock requestIdleCallback 立即执行
vi
.
stubGlobal
(
'
requestIdleCallback
'
,
(
cb
:
IdleRequestCallback
)
=>
{
const
id
=
setTimeout
(()
=>
cb
({
didTimeout
:
false
,
timeRemaining
:
()
=>
50
}),
0
)
return
id
})
vi
.
stubGlobal
(
'
cancelIdleCallback
'
,
(
id
:
number
)
=>
clearTimeout
(
id
))
})
afterEach
(()
=>
{
vi
.
restoreAllMocks
()
// 恢复原始函数
window
.
requestIdleCallback
=
originalRequestIdleCallback
window
.
cancelIdleCallback
=
originalCancelIdleCallback
})
describe
(
'
_isAdminRoute
'
,
()
=>
{
it
(
'
应该正确识别管理员路由
'
,
()
=>
{
const
{
_isAdminRoute
}
=
useRoutePrefetch
(
mockRouter
)
expect
(
_isAdminRoute
(
'
/admin/dashboard
'
)).
toBe
(
true
)
expect
(
_isAdminRoute
(
'
/admin/users
'
)).
toBe
(
true
)
expect
(
_isAdminRoute
(
'
/admin/accounts
'
)).
toBe
(
true
)
})
it
(
'
应该正确识别非管理员路由
'
,
()
=>
{
const
{
_isAdminRoute
}
=
useRoutePrefetch
(
mockRouter
)
expect
(
_isAdminRoute
(
'
/dashboard
'
)).
toBe
(
false
)
expect
(
_isAdminRoute
(
'
/keys
'
)).
toBe
(
false
)
expect
(
_isAdminRoute
(
'
/usage
'
)).
toBe
(
false
)
})
})
describe
(
'
_getPrefetchConfig
'
,
()
=>
{
it
(
'
管理员 dashboard 应该返回正确的预加载配置
'
,
()
=>
{
const
{
_getPrefetchConfig
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/admin/dashboard
'
)
const
config
=
_getPrefetchConfig
(
route
)
expect
(
config
).
toHaveLength
(
2
)
})
it
(
'
普通用户 dashboard 应该返回正确的预加载配置
'
,
()
=>
{
const
{
_getPrefetchConfig
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/dashboard
'
)
const
config
=
_getPrefetchConfig
(
route
)
expect
(
config
).
toHaveLength
(
2
)
})
it
(
'
未定义的路由应该返回空数组
'
,
()
=>
{
const
{
_getPrefetchConfig
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/unknown-route
'
)
const
config
=
_getPrefetchConfig
(
route
)
expect
(
config
).
toHaveLength
(
0
)
})
})
describe
(
'
triggerPrefetch
'
,
()
=>
{
it
(
'
应该在浏览器空闲时触发预加载
'
,
async
()
=>
{
const
{
triggerPrefetch
,
prefetchedRoutes
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/admin/dashboard
'
)
triggerPrefetch
(
route
)
// 等待 requestIdleCallback 执行
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
100
))
expect
(
prefetchedRoutes
.
value
.
has
(
'
/admin/dashboard
'
)).
toBe
(
true
)
})
it
(
'
应该避免重复预加载同一路由
'
,
async
()
=>
{
const
{
triggerPrefetch
,
prefetchedRoutes
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/admin/dashboard
'
)
triggerPrefetch
(
route
)
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
100
))
// 第二次触发
triggerPrefetch
(
route
)
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
100
))
// 只应该预加载一次
expect
(
prefetchedRoutes
.
value
.
size
).
toBe
(
1
)
})
})
describe
(
'
cancelPendingPrefetch
'
,
()
=>
{
it
(
'
应该取消挂起的预加载任务
'
,
()
=>
{
const
{
triggerPrefetch
,
cancelPendingPrefetch
,
prefetchedRoutes
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/admin/dashboard
'
)
triggerPrefetch
(
route
)
cancelPendingPrefetch
()
// 不应该有预加载完成
expect
(
prefetchedRoutes
.
value
.
size
).
toBe
(
0
)
})
})
describe
(
'
路由变化时取消之前的预加载
'
,
()
=>
{
it
(
'
应该在路由变化时取消之前的预加载任务
'
,
async
()
=>
{
const
{
triggerPrefetch
,
prefetchedRoutes
}
=
useRoutePrefetch
(
mockRouter
)
// 触发第一个路由的预加载
triggerPrefetch
(
createMockRoute
(
'
/admin/dashboard
'
))
// 立即切换到另一个路由
triggerPrefetch
(
createMockRoute
(
'
/admin/users
'
))
// 等待执行
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
100
))
// 只有最后一个路由应该被预加载
expect
(
prefetchedRoutes
.
value
.
has
(
'
/admin/users
'
)).
toBe
(
true
)
})
})
describe
(
'
resetPrefetchState
'
,
()
=>
{
it
(
'
应该重置所有预加载状态
'
,
async
()
=>
{
const
{
triggerPrefetch
,
resetPrefetchState
,
prefetchedRoutes
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/admin/dashboard
'
)
triggerPrefetch
(
route
)
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
100
))
expect
(
prefetchedRoutes
.
value
.
size
).
toBeGreaterThan
(
0
)
resetPrefetchState
()
expect
(
prefetchedRoutes
.
value
.
size
).
toBe
(
0
)
})
})
describe
(
'
预加载映射表
'
,
()
=>
{
it
(
'
管理员预加载映射表应该包含正确的路由
'
,
()
=>
{
expect
(
_adminPrefetchMap
).
toHaveProperty
(
'
/admin/dashboard
'
)
expect
(
_adminPrefetchMap
[
'
/admin/dashboard
'
]).
toHaveLength
(
2
)
})
it
(
'
用户预加载映射表应该包含正确的路由
'
,
()
=>
{
expect
(
_userPrefetchMap
).
toHaveProperty
(
'
/dashboard
'
)
expect
(
_userPrefetchMap
[
'
/dashboard
'
]).
toHaveLength
(
2
)
})
})
describe
(
'
requestIdleCallback 超时处理
'
,
()
=>
{
it
(
'
超时后仍能正常执行预加载
'
,
async
()
=>
{
// 模拟超时情况
vi
.
stubGlobal
(
'
requestIdleCallback
'
,
(
cb
:
IdleRequestCallback
,
options
?:
IdleRequestOptions
)
=>
{
const
timeout
=
options
?.
timeout
||
2000
return
setTimeout
(()
=>
cb
({
didTimeout
:
true
,
timeRemaining
:
()
=>
0
}),
timeout
)
})
const
{
triggerPrefetch
,
prefetchedRoutes
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/dashboard
'
)
triggerPrefetch
(
route
)
// 等待超时执行
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
2100
))
expect
(
prefetchedRoutes
.
value
.
has
(
'
/dashboard
'
)).
toBe
(
true
)
})
})
describe
(
'
预加载失败处理
'
,
()
=>
{
it
(
'
预加载失败时应该静默处理不影响页面功能
'
,
async
()
=>
{
const
{
triggerPrefetch
}
=
useRoutePrefetch
(
mockRouter
)
const
route
=
createMockRoute
(
'
/admin/dashboard
'
)
// 不应该抛出异常
expect
(()
=>
triggerPrefetch
(
route
)).
not
.
toThrow
()
})
})
describe
(
'
无 router 时的行为
'
,
()
=>
{
it
(
'
没有传入 router 时应该正常工作但不执行预加载
'
,
async
()
=>
{
const
{
triggerPrefetch
,
prefetchedRoutes
}
=
useRoutePrefetch
()
const
route
=
createMockRoute
(
'
/admin/dashboard
'
)
triggerPrefetch
(
route
)
await
new
Promise
((
resolve
)
=>
setTimeout
(
resolve
,
100
))
// 没有 router,无法获取组件,所以不会预加载
expect
(
prefetchedRoutes
.
value
.
size
).
toBe
(
0
)
})
})
})
frontend/src/composables/useNavigationLoading.ts
0 → 100644
View file @
dd7f2124
/**
* 导航加载状态组合式函数
* 管理路由切换时的加载状态,支持防闪烁逻辑
*/
import
{
ref
,
readonly
,
computed
}
from
'
vue
'
/**
* 导航加载状态管理
*
* 功能:
* 1. 在路由切换时显示加载状态
* 2. 快速导航(< 100ms)不显示加载指示器(防闪烁)
* 3. 导航取消时正确重置状态
*/
export
function
useNavigationLoading
()
{
// 内部加载状态
const
_isLoading
=
ref
(
false
)
// 导航开始时间(用于防闪烁计算)
let
navigationStartTime
:
number
|
null
=
null
// 防闪烁延迟计时器
let
showLoadingTimer
:
ReturnType
<
typeof
setTimeout
>
|
null
=
null
// 是否应该显示加载指示器(考虑防闪烁逻辑)
const
shouldShowLoading
=
ref
(
false
)
// 防闪烁延迟时间(毫秒)
const
ANTI_FLICKER_DELAY
=
100
/**
* 清理计时器
*/
const
clearTimer
=
():
void
=>
{
if
(
showLoadingTimer
!==
null
)
{
clearTimeout
(
showLoadingTimer
)
showLoadingTimer
=
null
}
}
/**
* 导航开始时调用
*/
const
startNavigation
=
():
void
=>
{
navigationStartTime
=
Date
.
now
()
_isLoading
.
value
=
true
// 延迟显示加载指示器,实现防闪烁
clearTimer
()
showLoadingTimer
=
setTimeout
(()
=>
{
if
(
_isLoading
.
value
)
{
shouldShowLoading
.
value
=
true
}
},
ANTI_FLICKER_DELAY
)
}
/**
* 导航结束时调用
*/
const
endNavigation
=
():
void
=>
{
clearTimer
()
_isLoading
.
value
=
false
shouldShowLoading
.
value
=
false
navigationStartTime
=
null
}
/**
* 导航取消时调用(比如快速连续点击不同链接)
*/
const
cancelNavigation
=
():
void
=>
{
clearTimer
()
// 保持加载状态,因为新的导航会立即开始
// 但重置导航开始时间
navigationStartTime
=
null
}
/**
* 重置所有状态(用于测试)
*/
const
resetState
=
():
void
=>
{
clearTimer
()
_isLoading
.
value
=
false
shouldShowLoading
.
value
=
false
navigationStartTime
=
null
}
/**
* 获取导航持续时间(毫秒)
*/
const
getNavigationDuration
=
():
number
|
null
=>
{
if
(
navigationStartTime
===
null
)
{
return
null
}
return
Date
.
now
()
-
navigationStartTime
}
// 公开的加载状态(只读)
const
isLoading
=
computed
(()
=>
shouldShowLoading
.
value
)
// 内部加载状态(用于测试,不考虑防闪烁)
const
isNavigating
=
readonly
(
_isLoading
)
return
{
isLoading
,
isNavigating
,
startNavigation
,
endNavigation
,
cancelNavigation
,
resetState
,
getNavigationDuration
,
// 导出常量用于测试
ANTI_FLICKER_DELAY
}
}
// 创建单例实例,供全局使用
let
navigationLoadingInstance
:
ReturnType
<
typeof
useNavigationLoading
>
|
null
=
null
export
function
useNavigationLoadingState
()
{
if
(
!
navigationLoadingInstance
)
{
navigationLoadingInstance
=
useNavigationLoading
()
}
return
navigationLoadingInstance
}
// 导出重置函数(用于测试)
export
function
_resetNavigationLoadingInstance
():
void
{
if
(
navigationLoadingInstance
)
{
navigationLoadingInstance
.
resetState
()
}
navigationLoadingInstance
=
null
}
frontend/src/composables/useRoutePrefetch.ts
0 → 100644
View file @
dd7f2124
/**
* 路由预加载组合式函数
* 在浏览器空闲时预加载可能访问的下一个页面,提升导航体验
*
* 优化说明:
* - 不使用静态 import() 映射表,避免增加入口文件大小
* - 通过路由配置动态获取组件的 import 函数
* - 只在实际需要预加载时才执行
*/
import
{
ref
,
readonly
}
from
'
vue
'
import
type
{
RouteLocationNormalized
,
Router
}
from
'
vue-router
'
/**
* 组件导入函数类型
*/
type
ComponentImportFn
=
()
=>
Promise
<
unknown
>
/**
* 预加载邻接表:定义每个路由应该预加载哪些相邻路由
* 只存储路由路径,不存储 import 函数,避免打包问题
*/
const
PREFETCH_ADJACENCY
:
Record
<
string
,
string
[]
>
=
{
// Admin routes - 预加载最常访问的相邻页面
'
/admin/dashboard
'
:
[
'
/admin/accounts
'
,
'
/admin/users
'
],
'
/admin/accounts
'
:
[
'
/admin/dashboard
'
,
'
/admin/users
'
],
'
/admin/users
'
:
[
'
/admin/groups
'
,
'
/admin/dashboard
'
],
'
/admin/groups
'
:
[
'
/admin/subscriptions
'
,
'
/admin/users
'
],
'
/admin/subscriptions
'
:
[
'
/admin/groups
'
,
'
/admin/redeem
'
],
// User routes
'
/dashboard
'
:
[
'
/keys
'
,
'
/usage
'
],
'
/keys
'
:
[
'
/dashboard
'
,
'
/usage
'
],
'
/usage
'
:
[
'
/keys
'
,
'
/redeem
'
],
'
/redeem
'
:
[
'
/usage
'
,
'
/profile
'
],
'
/profile
'
:
[
'
/dashboard
'
,
'
/keys
'
]
}
/**
* requestIdleCallback 的返回类型
*/
type
IdleCallbackHandle
=
number
|
ReturnType
<
typeof
setTimeout
>
/**
* requestIdleCallback polyfill (Safari < 15)
*/
const
scheduleIdleCallback
=
(
callback
:
IdleRequestCallback
,
options
?:
IdleRequestOptions
):
IdleCallbackHandle
=>
{
if
(
typeof
window
.
requestIdleCallback
===
'
function
'
)
{
return
window
.
requestIdleCallback
(
callback
,
options
)
}
return
setTimeout
(()
=>
{
callback
({
didTimeout
:
false
,
timeRemaining
:
()
=>
50
})
},
1000
)
}
const
cancelScheduledCallback
=
(
handle
:
IdleCallbackHandle
):
void
=>
{
if
(
typeof
window
.
cancelIdleCallback
===
'
function
'
&&
typeof
handle
===
'
number
'
)
{
window
.
cancelIdleCallback
(
handle
)
}
else
{
clearTimeout
(
handle
)
}
}
/**
* 路由预加载组合式函数
*
* @param router - Vue Router 实例,用于获取路由组件
*/
export
function
useRoutePrefetch
(
router
?:
Router
)
{
// 当前挂起的预加载任务句柄
const
pendingPrefetchHandle
=
ref
<
IdleCallbackHandle
|
null
>
(
null
)
// 已预加载的路由集合
const
prefetchedRoutes
=
ref
<
Set
<
string
>>
(
new
Set
())
/**
* 从路由配置中获取组件的 import 函数
*/
const
getComponentImporter
=
(
path
:
string
):
ComponentImportFn
|
null
=>
{
if
(
!
router
)
return
null
const
routes
=
router
.
getRoutes
()
const
route
=
routes
.
find
((
r
)
=>
r
.
path
===
path
)
if
(
route
&&
route
.
components
?.
default
)
{
const
component
=
route
.
components
.
default
// 检查是否是懒加载组件(函数形式)
if
(
typeof
component
===
'
function
'
)
{
return
component
as
ComponentImportFn
}
}
return
null
}
/**
* 获取当前路由应该预加载的路由路径列表
*/
const
getPrefetchPaths
=
(
route
:
RouteLocationNormalized
):
string
[]
=>
{
return
PREFETCH_ADJACENCY
[
route
.
path
]
||
[]
}
/**
* 执行单个组件的预加载
*/
const
prefetchComponent
=
async
(
importFn
:
ComponentImportFn
):
Promise
<
void
>
=>
{
try
{
await
importFn
()
}
catch
(
error
)
{
// 静默处理预加载错误
if
(
import
.
meta
.
env
.
DEV
)
{
console
.
debug
(
'
[Prefetch] Failed to prefetch component:
'
,
error
)
}
}
}
/**
* 取消挂起的预加载任务
*/
const
cancelPendingPrefetch
=
():
void
=>
{
if
(
pendingPrefetchHandle
.
value
!==
null
)
{
cancelScheduledCallback
(
pendingPrefetchHandle
.
value
)
pendingPrefetchHandle
.
value
=
null
}
}
/**
* 触发路由预加载
*/
const
triggerPrefetch
=
(
route
:
RouteLocationNormalized
):
void
=>
{
cancelPendingPrefetch
()
const
prefetchPaths
=
getPrefetchPaths
(
route
)
if
(
prefetchPaths
.
length
===
0
)
return
pendingPrefetchHandle
.
value
=
scheduleIdleCallback
(
()
=>
{
pendingPrefetchHandle
.
value
=
null
const
routePath
=
route
.
path
if
(
prefetchedRoutes
.
value
.
has
(
routePath
))
return
// 获取需要预加载的组件 import 函数
const
importFns
:
ComponentImportFn
[]
=
[]
for
(
const
path
of
prefetchPaths
)
{
const
importFn
=
getComponentImporter
(
path
)
if
(
importFn
)
{
importFns
.
push
(
importFn
)
}
}
if
(
importFns
.
length
>
0
)
{
Promise
.
all
(
importFns
.
map
(
prefetchComponent
)).
then
(()
=>
{
prefetchedRoutes
.
value
.
add
(
routePath
)
})
}
},
{
timeout
:
2000
}
)
}
/**
* 重置预加载状态
*/
const
resetPrefetchState
=
():
void
=>
{
cancelPendingPrefetch
()
prefetchedRoutes
.
value
.
clear
()
}
/**
* 判断是否为管理员路由
*/
const
isAdminRoute
=
(
path
:
string
):
boolean
=>
{
return
path
.
startsWith
(
'
/admin
'
)
}
/**
* 获取预加载配置(兼容旧 API)
*/
const
getPrefetchConfig
=
(
route
:
RouteLocationNormalized
):
ComponentImportFn
[]
=>
{
const
paths
=
getPrefetchPaths
(
route
)
const
importFns
:
ComponentImportFn
[]
=
[]
for
(
const
path
of
paths
)
{
const
importFn
=
getComponentImporter
(
path
)
if
(
importFn
)
importFns
.
push
(
importFn
)
}
return
importFns
}
return
{
prefetchedRoutes
:
readonly
(
prefetchedRoutes
),
triggerPrefetch
,
cancelPendingPrefetch
,
resetPrefetchState
,
_getPrefetchConfig
:
getPrefetchConfig
,
_isAdminRoute
:
isAdminRoute
}
}
// 兼容旧测试的导出
export
const
_adminPrefetchMap
=
PREFETCH_ADJACENCY
export
const
_userPrefetchMap
=
PREFETCH_ADJACENCY
frontend/src/i18n/locales/en.ts
View file @
dd7f2124
...
@@ -163,6 +163,7 @@ export default {
...
@@ -163,6 +163,7 @@ export default {
notAvailable
:
'
N/A
'
,
notAvailable
:
'
N/A
'
,
now
:
'
Now
'
,
now
:
'
Now
'
,
unknown
:
'
Unknown
'
,
unknown
:
'
Unknown
'
,
minutes
:
'
min
'
,
time
:
{
time
:
{
never
:
'
Never
'
,
never
:
'
Never
'
,
justNow
:
'
Just now
'
,
justNow
:
'
Just now
'
,
...
@@ -1082,7 +1083,7 @@ export default {
...
@@ -1082,7 +1083,7 @@ export default {
platformType
:
'
Platform/Type
'
,
platformType
:
'
Platform/Type
'
,
platform
:
'
Platform
'
,
platform
:
'
Platform
'
,
type
:
'
Type
'
,
type
:
'
Type
'
,
c
oncurrencyStatus
:
'
Concurrenc
y
'
,
c
apacity
:
'
Capacit
y
'
,
notes
:
'
Notes
'
,
notes
:
'
Notes
'
,
priority
:
'
Priority
'
,
priority
:
'
Priority
'
,
billingRateMultiplier
:
'
Billing Rate
'
,
billingRateMultiplier
:
'
Billing Rate
'
,
...
@@ -1096,6 +1097,18 @@ export default {
...
@@ -1096,6 +1097,18 @@ export default {
expiresAt
:
'
Expires At
'
,
expiresAt
:
'
Expires At
'
,
actions
:
'
Actions
'
actions
:
'
Actions
'
},
},
// Capacity status tooltips
capacity
:
{
windowCost
:
{
blocked
:
'
5h window cost exceeded, account scheduling paused
'
,
stickyOnly
:
'
5h window cost at threshold, only sticky sessions allowed
'
,
normal
:
'
5h window cost normal
'
},
sessions
:
{
full
:
'
Active sessions full, new sessions must wait (idle timeout: {idle} min)
'
,
normal
:
'
Active sessions normal (idle timeout: {idle} min)
'
}
},
tempUnschedulable
:
{
tempUnschedulable
:
{
title
:
'
Temp Unschedulable
'
,
title
:
'
Temp Unschedulable
'
,
statusTitle
:
'
Temp Unschedulable Status
'
,
statusTitle
:
'
Temp Unschedulable Status
'
,
...
@@ -1247,6 +1260,31 @@ export default {
...
@@ -1247,6 +1260,31 @@ export default {
'
When enabled, warmup requests like title generation will return mock responses without consuming upstream tokens
'
,
'
When enabled, warmup requests like title generation will return mock responses without consuming upstream tokens
'
,
autoPauseOnExpired
:
'
Auto Pause On Expired
'
,
autoPauseOnExpired
:
'
Auto Pause On Expired
'
,
autoPauseOnExpiredDesc
:
'
When enabled, the account will auto pause scheduling after it expires
'
,
autoPauseOnExpiredDesc
:
'
When enabled, the account will auto pause scheduling after it expires
'
,
// Quota control (Anthropic OAuth/SetupToken only)
quotaControl
:
{
title
:
'
Quota Control
'
,
hint
:
'
Only applies to Anthropic OAuth/Setup Token accounts
'
,
windowCost
:
{
label
:
'
5h Window Cost Limit
'
,
hint
:
'
Limit account cost usage within the 5-hour window
'
,
limit
:
'
Cost Threshold
'
,
limitPlaceholder
:
'
50
'
,
limitHint
:
'
Account will not participate in new scheduling after reaching threshold
'
,
stickyReserve
:
'
Sticky Reserve
'
,
stickyReservePlaceholder
:
'
10
'
,
stickyReserveHint
:
'
Additional reserve for sticky sessions
'
},
sessionLimit
:
{
label
:
'
Session Count Limit
'
,
hint
:
'
Limit the number of active concurrent sessions
'
,
maxSessions
:
'
Max Sessions
'
,
maxSessionsPlaceholder
:
'
3
'
,
maxSessionsHint
:
'
Maximum number of active concurrent sessions
'
,
idleTimeout
:
'
Idle Timeout
'
,
idleTimeoutPlaceholder
:
'
5
'
,
idleTimeoutHint
:
'
Sessions will be released after idle timeout
'
}
},
expired
:
'
Expired
'
,
expired
:
'
Expired
'
,
proxy
:
'
Proxy
'
,
proxy
:
'
Proxy
'
,
noProxy
:
'
No Proxy
'
,
noProxy
:
'
No Proxy
'
,
...
...
frontend/src/i18n/locales/zh.ts
View file @
dd7f2124
...
@@ -160,6 +160,7 @@ export default {
...
@@ -160,6 +160,7 @@ export default {
notAvailable
:
'
不可用
'
,
notAvailable
:
'
不可用
'
,
now
:
'
现在
'
,
now
:
'
现在
'
,
unknown
:
'
未知
'
,
unknown
:
'
未知
'
,
minutes
:
'
分钟
'
,
time
:
{
time
:
{
never
:
'
从未
'
,
never
:
'
从未
'
,
justNow
:
'
刚刚
'
,
justNow
:
'
刚刚
'
,
...
@@ -1131,7 +1132,7 @@ export default {
...
@@ -1131,7 +1132,7 @@ export default {
platformType
:
'
平台/类型
'
,
platformType
:
'
平台/类型
'
,
platform
:
'
平台
'
,
platform
:
'
平台
'
,
type
:
'
类型
'
,
type
:
'
类型
'
,
c
oncurrencyStatus
:
'
并发
'
,
c
apacity
:
'
容量
'
,
notes
:
'
备注
'
,
notes
:
'
备注
'
,
priority
:
'
优先级
'
,
priority
:
'
优先级
'
,
billingRateMultiplier
:
'
账号倍率
'
,
billingRateMultiplier
:
'
账号倍率
'
,
...
@@ -1145,6 +1146,18 @@ export default {
...
@@ -1145,6 +1146,18 @@ export default {
expiresAt
:
'
过期时间
'
,
expiresAt
:
'
过期时间
'
,
actions
:
'
操作
'
actions
:
'
操作
'
},
},
// 容量状态提示
capacity
:
{
windowCost
:
{
blocked
:
'
5h窗口费用超限,账号暂停调度
'
,
stickyOnly
:
'
5h窗口费用达阈值,仅允许粘性会话
'
,
normal
:
'
5h窗口费用正常
'
},
sessions
:
{
full
:
'
活跃会话已满,新会话需等待(空闲超时:{idle}分钟)
'
,
normal
:
'
活跃会话正常(空闲超时:{idle}分钟)
'
}
},
clearRateLimit
:
'
清除速率限制
'
,
clearRateLimit
:
'
清除速率限制
'
,
testConnection
:
'
测试连接
'
,
testConnection
:
'
测试连接
'
,
reAuthorize
:
'
重新授权
'
,
reAuthorize
:
'
重新授权
'
,
...
@@ -1380,6 +1393,31 @@ export default {
...
@@ -1380,6 +1393,31 @@ export default {
interceptWarmupRequestsDesc
:
'
启用后,标题生成等预热请求将返回 mock 响应,不消耗上游 token
'
,
interceptWarmupRequestsDesc
:
'
启用后,标题生成等预热请求将返回 mock 响应,不消耗上游 token
'
,
autoPauseOnExpired
:
'
过期自动暂停调度
'
,
autoPauseOnExpired
:
'
过期自动暂停调度
'
,
autoPauseOnExpiredDesc
:
'
启用后,账号过期将自动暂停调度
'
,
autoPauseOnExpiredDesc
:
'
启用后,账号过期将自动暂停调度
'
,
// Quota control (Anthropic OAuth/SetupToken only)
quotaControl
:
{
title
:
'
配额控制
'
,
hint
:
'
仅适用于 Anthropic OAuth/Setup Token 账号
'
,
windowCost
:
{
label
:
'
5h窗口费用控制
'
,
hint
:
'
限制账号在5小时窗口内的费用使用
'
,
limit
:
'
费用阈值
'
,
limitPlaceholder
:
'
50
'
,
limitHint
:
'
达到阈值后不参与新请求调度
'
,
stickyReserve
:
'
粘性预留额度
'
,
stickyReservePlaceholder
:
'
10
'
,
stickyReserveHint
:
'
为粘性会话预留的额外额度
'
},
sessionLimit
:
{
label
:
'
会话数量控制
'
,
hint
:
'
限制同时活跃的会话数量
'
,
maxSessions
:
'
最大会话数
'
,
maxSessionsPlaceholder
:
'
3
'
,
maxSessionsHint
:
'
同时活跃的最大会话数量
'
,
idleTimeout
:
'
空闲超时
'
,
idleTimeoutPlaceholder
:
'
5
'
,
idleTimeoutHint
:
'
会话空闲超时后自动释放
'
}
},
expired
:
'
已过期
'
,
expired
:
'
已过期
'
,
proxy
:
'
代理
'
,
proxy
:
'
代理
'
,
noProxy
:
'
无代理
'
,
noProxy
:
'
无代理
'
,
...
...
frontend/src/router/index.ts
View file @
dd7f2124
...
@@ -6,6 +6,8 @@
...
@@ -6,6 +6,8 @@
import
{
createRouter
,
createWebHistory
,
type
RouteRecordRaw
}
from
'
vue-router
'
import
{
createRouter
,
createWebHistory
,
type
RouteRecordRaw
}
from
'
vue-router
'
import
{
useAuthStore
}
from
'
@/stores/auth
'
import
{
useAuthStore
}
from
'
@/stores/auth
'
import
{
useAppStore
}
from
'
@/stores/app
'
import
{
useAppStore
}
from
'
@/stores/app
'
import
{
useNavigationLoadingState
}
from
'
@/composables/useNavigationLoading
'
import
{
useRoutePrefetch
}
from
'
@/composables/useRoutePrefetch
'
/**
/**
* Route definitions with lazy loading
* Route definitions with lazy loading
...
@@ -326,7 +328,15 @@ const router = createRouter({
...
@@ -326,7 +328,15 @@ const router = createRouter({
*/
*/
let
authInitialized
=
false
let
authInitialized
=
false
// 初始化导航加载状态和预加载
const
navigationLoading
=
useNavigationLoadingState
()
// 延迟初始化预加载,传入 router 实例
let
routePrefetch
:
ReturnType
<
typeof
useRoutePrefetch
>
|
null
=
null
router
.
beforeEach
((
to
,
_from
,
next
)
=>
{
router
.
beforeEach
((
to
,
_from
,
next
)
=>
{
// 开始导航加载状态
navigationLoading
.
startNavigation
()
const
authStore
=
useAuthStore
()
const
authStore
=
useAuthStore
()
// Restore auth state from localStorage on first navigation (page refresh)
// Restore auth state from localStorage on first navigation (page refresh)
...
@@ -398,6 +408,21 @@ router.beforeEach((to, _from, next) => {
...
@@ -398,6 +408,21 @@ router.beforeEach((to, _from, next) => {
next
()
next
()
})
})
/**
* Navigation guard: End loading and trigger prefetch
*/
router
.
afterEach
((
to
)
=>
{
// 结束导航加载状态
navigationLoading
.
endNavigation
()
// 懒初始化预加载(首次导航时创建,传入 router 实例)
if
(
!
routePrefetch
)
{
routePrefetch
=
useRoutePrefetch
(
router
)
}
// 触发路由预加载(在浏览器空闲时执行)
routePrefetch
.
triggerPrefetch
(
to
)
})
/**
/**
* Navigation guard: Error handling
* Navigation guard: Error handling
* Handles dynamic import failures caused by deployment updates
* Handles dynamic import failures caused by deployment updates
...
...
frontend/src/style.css
View file @
dd7f2124
@import
url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap')
;
@tailwind
base
;
@tailwind
base
;
@tailwind
components
;
@tailwind
components
;
@tailwind
utilities
;
@tailwind
utilities
;
...
@@ -11,7 +9,6 @@
...
@@ -11,7 +9,6 @@
html
{
html
{
@apply
scroll-smooth
antialiased;
@apply
scroll-smooth
antialiased;
font-feature-settings
:
'cv02'
,
'cv03'
,
'cv04'
,
'cv11'
;
}
}
body
{
body
{
...
...
frontend/src/types/index.ts
View file @
dd7f2124
...
@@ -471,6 +471,18 @@ export interface Account {
...
@@ -471,6 +471,18 @@ export interface Account {
session_window_start
:
string
|
null
session_window_start
:
string
|
null
session_window_end
:
string
|
null
session_window_end
:
string
|
null
session_window_status
:
'
allowed
'
|
'
allowed_warning
'
|
'
rejected
'
|
null
session_window_status
:
'
allowed
'
|
'
allowed_warning
'
|
'
rejected
'
|
null
// 5h窗口费用控制(仅 Anthropic OAuth/SetupToken 账号有效)
window_cost_limit
?:
number
|
null
window_cost_sticky_reserve
?:
number
|
null
// 会话数量控制(仅 Anthropic OAuth/SetupToken 账号有效)
max_sessions
?:
number
|
null
session_idle_timeout_minutes
?:
number
|
null
// 运行时状态(仅当启用对应限制时返回)
current_window_cost
?:
number
|
null
// 当前窗口费用
active_sessions
?:
number
|
null
// 当前活跃会话数
}
}
// Account Usage types
// Account Usage types
...
...
frontend/src/views/admin/AccountsView.vue
View file @
dd7f2124
...
@@ -34,15 +34,8 @@
...
@@ -34,15 +34,8 @@
<
template
#cell-platform_type=
"{ row }"
>
<
template
#cell-platform_type=
"{ row }"
>
<PlatformTypeBadge
:platform=
"row.platform"
:type=
"row.type"
/>
<PlatformTypeBadge
:platform=
"row.platform"
:type=
"row.type"
/>
</
template
>
</
template
>
<
template
#cell-concurrency=
"{ row }"
>
<
template
#cell-capacity=
"{ row }"
>
<div
class=
"flex items-center gap-1.5"
>
<AccountCapacityCell
:account=
"row"
/>
<span
:class=
"['inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium', (row.current_concurrency || 0) >= row.concurrency ? 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400' : (row.current_concurrency || 0) > 0 ? 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400' : 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400']"
>
<svg
class=
"h-3 w-3"
fill=
"none"
viewBox=
"0 0 24 24"
stroke=
"currentColor"
stroke-width=
"2"
><path
stroke-linecap=
"round"
stroke-linejoin=
"round"
d=
"M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"
/></svg>
<span
class=
"font-mono"
>
{{
row
.
current_concurrency
||
0
}}
</span>
<span
class=
"text-gray-400 dark:text-gray-500"
>
/
</span>
<span
class=
"font-mono"
>
{{
row
.
concurrency
}}
</span>
</span>
</div>
</
template
>
</
template
>
<
template
#cell-status=
"{ row }"
>
<
template
#cell-status=
"{ row }"
>
<AccountStatusIndicator
:account=
"row"
@
show-temp-unsched=
"handleShowTempUnsched"
/>
<AccountStatusIndicator
:account=
"row"
@
show-temp-unsched=
"handleShowTempUnsched"
/>
...
@@ -148,6 +141,7 @@ import AccountStatusIndicator from '@/components/account/AccountStatusIndicator.
...
@@ -148,6 +141,7 @@ import AccountStatusIndicator from '@/components/account/AccountStatusIndicator.
import
AccountUsageCell
from
'
@/components/account/AccountUsageCell.vue
'
import
AccountUsageCell
from
'
@/components/account/AccountUsageCell.vue
'
import
AccountTodayStatsCell
from
'
@/components/account/AccountTodayStatsCell.vue
'
import
AccountTodayStatsCell
from
'
@/components/account/AccountTodayStatsCell.vue
'
import
AccountGroupsCell
from
'
@/components/account/AccountGroupsCell.vue
'
import
AccountGroupsCell
from
'
@/components/account/AccountGroupsCell.vue
'
import
AccountCapacityCell
from
'
@/components/account/AccountCapacityCell.vue
'
import
PlatformTypeBadge
from
'
@/components/common/PlatformTypeBadge.vue
'
import
PlatformTypeBadge
from
'
@/components/common/PlatformTypeBadge.vue
'
import
{
formatDateTime
,
formatRelativeTime
}
from
'
@/utils/format
'
import
{
formatDateTime
,
formatRelativeTime
}
from
'
@/utils/format
'
import
type
{
Account
,
Proxy
,
Group
}
from
'
@/types
'
import
type
{
Account
,
Proxy
,
Group
}
from
'
@/types
'
...
@@ -187,7 +181,7 @@ const cols = computed(() => {
...
@@ -187,7 +181,7 @@ const cols = computed(() => {
{
key
:
'
select
'
,
label
:
''
,
sortable
:
false
},
{
key
:
'
select
'
,
label
:
''
,
sortable
:
false
},
{
key
:
'
name
'
,
label
:
t
(
'
admin.accounts.columns.name
'
),
sortable
:
true
},
{
key
:
'
name
'
,
label
:
t
(
'
admin.accounts.columns.name
'
),
sortable
:
true
},
{
key
:
'
platform_type
'
,
label
:
t
(
'
admin.accounts.columns.platformType
'
),
sortable
:
false
},
{
key
:
'
platform_type
'
,
label
:
t
(
'
admin.accounts.columns.platformType
'
),
sortable
:
false
},
{
key
:
'
c
oncurrenc
y
'
,
label
:
t
(
'
admin.accounts.columns.c
oncurrencyStatus
'
),
sortable
:
false
},
{
key
:
'
c
apacit
y
'
,
label
:
t
(
'
admin.accounts.columns.c
apacity
'
),
sortable
:
false
},
{
key
:
'
status
'
,
label
:
t
(
'
admin.accounts.columns.status
'
),
sortable
:
true
},
{
key
:
'
status
'
,
label
:
t
(
'
admin.accounts.columns.status
'
),
sortable
:
true
},
{
key
:
'
schedulable
'
,
label
:
t
(
'
admin.accounts.columns.schedulable
'
),
sortable
:
true
},
{
key
:
'
schedulable
'
,
label
:
t
(
'
admin.accounts.columns.schedulable
'
),
sortable
:
true
},
{
key
:
'
today_stats
'
,
label
:
t
(
'
admin.accounts.columns.todayStats
'
),
sortable
:
false
}
{
key
:
'
today_stats
'
,
label
:
t
(
'
admin.accounts.columns.todayStats
'
),
sortable
:
false
}
...
...
frontend/tailwind.config.js
View file @
dd7f2124
...
@@ -50,16 +50,19 @@ export default {
...
@@ -50,16 +50,19 @@ export default {
},
},
fontFamily
:
{
fontFamily
:
{
sans
:
[
sans
:
[
'
Inter
'
,
'
system-ui
'
,
'
-apple-system
'
,
'
-apple-system
'
,
'
BlinkMacSystemFont
'
,
'
BlinkMacSystemFont
'
,
'
Segoe UI
'
,
'
Segoe UI
'
,
'
Roboto
'
,
'
Roboto
'
,
'
Helvetica Neue
'
,
'
Helvetica Neue
'
,
'
Arial
'
,
'
Arial
'
,
'
PingFang SC
'
,
'
Hiragino Sans GB
'
,
'
Microsoft YaHei
'
,
'
sans-serif
'
'
sans-serif
'
],
],
mono
:
[
'
JetBrains Mono
'
,
'
Fira Code
'
,
'
Monaco
'
,
'
Consolas
'
,
'
monospace
'
]
mono
:
[
'
ui-monospace
'
,
'
SFMono-Regular
'
,
'
Menlo
'
,
'
Monaco
'
,
'
Consolas
'
,
'
monospace
'
]
},
},
boxShadow
:
{
boxShadow
:
{
glass
:
'
0 8px 32px rgba(0, 0, 0, 0.08)
'
,
glass
:
'
0 8px 32px rgba(0, 0, 0, 0.08)
'
,
...
...
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment