Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a857b93b7 | ||
|
|
ee42a9d0ed | ||
|
|
28976dea4b | ||
|
|
22e5cc3aa5 | ||
|
|
3052c0b23e | ||
|
|
1c9cabf7e7 | ||
|
|
03842d1741 |
+1
-1
@@ -17,7 +17,7 @@
|
||||
"@ant-design/pro-components": "3.1.0-0",
|
||||
"@antv/g6": "^5.0.51",
|
||||
"@braintree/sanitize-url": "^7.1.1",
|
||||
"@gpustack/core-ui": "^1.0.27",
|
||||
"@gpustack/core-ui": "^1.0.32",
|
||||
"@huggingface/gguf": "^0.1.7",
|
||||
"@huggingface/hub": "^0.15.1",
|
||||
"@huggingface/tasks": "^0.11.6",
|
||||
|
||||
Generated
+117
-117
@@ -24,8 +24,8 @@ importers:
|
||||
specifier: ^7.1.1
|
||||
version: 7.1.2
|
||||
'@gpustack/core-ui':
|
||||
specifier: ^1.0.27
|
||||
version: 1.0.27(czdvzceysqw7iv6pct2ucnb23e)
|
||||
specifier: ^1.0.32
|
||||
version: 1.0.32(czdvzceysqw7iv6pct2ucnb23e)
|
||||
'@huggingface/gguf':
|
||||
specifier: ^0.1.7
|
||||
version: 0.1.18
|
||||
@@ -49,7 +49,7 @@ importers:
|
||||
version: 4.17.24
|
||||
'@umijs/max':
|
||||
specifier: ^4.6.15
|
||||
version: 4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(lightningcss@1.22.1)(prettier@3.8.3)(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
version: 4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(lightningcss@1.22.1)(prettier@3.8.3)(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@xterm/addon-fit':
|
||||
specifier: ^0.10.0
|
||||
version: 0.10.0(@xterm/xterm@5.5.0)
|
||||
@@ -109,7 +109,7 @@ importers:
|
||||
version: 3.3.0
|
||||
jotai:
|
||||
specifier: ^2.8.4
|
||||
version: 2.20.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@18.3.28)(react@18.3.1)
|
||||
version: 2.20.0(@babel/core@7.23.6)(@babel/template@7.28.6)(@types/react@18.3.28)(react@18.3.1)
|
||||
js-yaml:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.1
|
||||
@@ -205,7 +205,7 @@ importers:
|
||||
version: 6.4.1(css-to-react-native@3.2.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
umi-presets-pro:
|
||||
specifier: ^2.0.3
|
||||
version: 2.0.3(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(chokidar@3.6.0)(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(umi@4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))
|
||||
version: 2.0.3(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(chokidar@3.6.0)(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(umi@4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))
|
||||
wavesurfer.js:
|
||||
specifier: ^7.8.8
|
||||
version: 7.12.6
|
||||
@@ -233,10 +233,10 @@ importers:
|
||||
version: 1.0.1
|
||||
'@umijs/plugins':
|
||||
specifier: ^4.4.11
|
||||
version: 4.6.51(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
version: 4.6.51(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
babel-plugin-named-asset-import:
|
||||
specifier: ^0.3.8
|
||||
version: 0.3.8(@babel/core@7.29.0)
|
||||
version: 0.3.8(@babel/core@7.23.6)
|
||||
case-sensitive-paths-webpack-plugin:
|
||||
specifier: ^2.4.0
|
||||
version: 2.4.0
|
||||
@@ -1484,24 +1484,24 @@ packages:
|
||||
resolution: {integrity: sha512-KWk80UPIzPmUg+P0rKh6TqspRw0G6eux1PuJr+zz47ftMaZ9QDwbGzHZbtzWkl5hgayM/qrKRutllRC7D/vVXQ==, tarball: https://registry.npmjs.org/@formatjs/intl-utils/-/intl-utils-2.3.0.tgz}
|
||||
deprecated: the package is rather renamed to @formatjs/ecma-abstract with some changes in functionality (primarily selectUnit is removed and we don't plan to make any further changes to this package
|
||||
|
||||
'@gpustack/core-ui@1.0.27':
|
||||
resolution: {integrity: sha512-m3ue0EHFKULla0mpnpxZwn9LVaGKS+HnuzQYSBECQa4vaP8MEEQsR7oFBtG8bhWUWYA9VzP6k7fjozDkP6TymA==, tarball: https://registry.npmjs.org/@gpustack/core-ui/-/core-ui-1.0.27.tgz}
|
||||
'@gpustack/core-ui@1.0.32':
|
||||
resolution: {integrity: sha512-kGTazoqbK2KyZgOP6gmQaRxTiQVfF2IKLGDXjJq6w6BbmJgALXFJA2v2ROjAbjEVyfTdBzyYeXfPo/JgISpMNw==, tarball: https://registry.npmjs.org/@gpustack/core-ui/-/core-ui-1.0.32.tgz}
|
||||
peerDependencies:
|
||||
'@ant-design/icons': '>=6.0.0'
|
||||
'@ant-design/icons': ^6.1.0
|
||||
'@ant-design/pro-components': 3.1.0-0
|
||||
'@monaco-editor/react': ^4.6.0
|
||||
ahooks: '>=3.0.0'
|
||||
antd: '>=6.0.0'
|
||||
antd-style: '>=3.0.0'
|
||||
axios: '>=1.8.0'
|
||||
echarts: '>=5.0.0'
|
||||
ahooks: ^3.8.5
|
||||
antd: ^6.3.3
|
||||
antd-style: ^3.6.2
|
||||
axios: ^1.8.2
|
||||
echarts: ^5.5.1
|
||||
file-saver: ^2.0.5
|
||||
monaco-editor: ^0.30.1
|
||||
monaco-yaml: ^4.0.0
|
||||
overlayscrollbars-react: ^0.5.6
|
||||
react: '>=18.0.0'
|
||||
react-dom: '>=18.0.0'
|
||||
styled-components: '>=6.0.0'
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
styled-components: ^6.1.15
|
||||
|
||||
'@hono/node-server@1.19.14':
|
||||
resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==, tarball: https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz}
|
||||
@@ -9257,14 +9257,14 @@ snapshots:
|
||||
'@radix-ui/popper': 0.0.10
|
||||
react: 18.3.1
|
||||
|
||||
'@alita/plugins@3.5.5(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@alita/plugins@3.5.5(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@alita/babel-transform-jsx-class': 0.0.2
|
||||
'@alita/inspx': 0.0.2(react@18.3.1)
|
||||
'@alita/request': 3.1.2
|
||||
'@alita/types': 3.1.2
|
||||
'@umijs/bundler-utils': 4.4.11
|
||||
'@umijs/plugins': 4.4.11(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@umijs/plugins': 4.4.11(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@umijs/utils': 4.4.11
|
||||
ahooks: 3.9.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
antd-mobile-alita: 2.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -10134,90 +10134,90 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)':
|
||||
'@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
|
||||
'@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.29.0)':
|
||||
'@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/helper-module-transforms': 7.28.6(@babel/core@7.23.6)
|
||||
'@babel/helper-plugin-utils': 7.28.6
|
||||
'@babel/helper-simple-access': 7.27.1
|
||||
transitivePeerDependencies:
|
||||
@@ -10808,7 +10808,7 @@ snapshots:
|
||||
|
||||
'@formatjs/intl-utils@2.3.0': {}
|
||||
|
||||
'@gpustack/core-ui@1.0.27(czdvzceysqw7iv6pct2ucnb23e)':
|
||||
'@gpustack/core-ui@1.0.32(czdvzceysqw7iv6pct2ucnb23e)':
|
||||
dependencies:
|
||||
'@ant-design/icons': 6.2.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@ant-design/pro-components': 3.1.0-0(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -12281,11 +12281,11 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@umijs/bundler-utoopack@4.6.51(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))':
|
||||
'@umijs/bundler-utoopack@4.6.51(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))':
|
||||
dependencies:
|
||||
'@umijs/bundler-utils': 4.6.51
|
||||
'@umijs/bundler-webpack': 4.6.51(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@utoo/pack': 1.4.3(less-loader@11.1.0(less@4.1.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))(less@4.1.3)(postcss@8.5.14)(resolve-url-loader@5.0.0)(sass-loader@13.2.0(sass@1.54.0)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))
|
||||
'@utoo/pack': 1.4.3(less-loader@11.1.0(less@4.1.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))(less@4.1.3)(postcss@8.5.14)(resolve-url-loader@5.0.0)(sass-loader@13.2.0(sass@1.54.0)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))
|
||||
compression: 1.8.1
|
||||
connect-history-api-fallback: 2.0.0
|
||||
cors: 2.8.6
|
||||
@@ -12553,14 +12553,14 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@umijs/max@4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(lightningcss@1.22.1)(prettier@3.8.3)(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))':
|
||||
'@umijs/max@4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(lightningcss@1.22.1)(prettier@3.8.3)(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))':
|
||||
dependencies:
|
||||
'@umijs/lint': 4.6.51(eslint@8.35.0)(stylelint@14.8.2)(typescript@5.9.3)
|
||||
'@umijs/plugins': 4.6.51(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@4.24.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@umijs/plugins': 4.6.51(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@4.24.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
antd: 4.24.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
eslint: 8.35.0
|
||||
stylelint: 14.8.2
|
||||
umi: 4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@8.35.0)(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
umi: 4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@8.35.0)(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- '@rspack/core'
|
||||
@@ -12642,7 +12642,7 @@ snapshots:
|
||||
dependencies:
|
||||
tsx: 3.12.2
|
||||
|
||||
'@umijs/plugins@4.4.11(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@umijs/plugins@4.4.11(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ahooksjs/use-request': 2.8.15(react@18.3.1)
|
||||
'@ant-design/antd-theme-variable': 1.0.0
|
||||
@@ -12657,7 +12657,7 @@ snapshots:
|
||||
antd-dayjs-webpack-plugin: 1.0.6(dayjs@1.11.20)
|
||||
axios: 0.27.2
|
||||
babel-plugin-import: 1.13.8
|
||||
babel-plugin-styled-components: 2.1.4(@babel/core@7.29.0)(styled-components@6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
babel-plugin-styled-components: 2.1.4(@babel/core@7.23.6)(styled-components@6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
dayjs: 1.11.20
|
||||
dva-core: 2.0.4(redux@4.2.1)
|
||||
dva-immer: 1.0.2(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
@@ -12687,7 +12687,7 @@ snapshots:
|
||||
- react-native
|
||||
- supports-color
|
||||
|
||||
'@umijs/plugins@4.6.51(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@4.24.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@umijs/plugins@4.6.51(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@4.24.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ahooksjs/use-request': 2.8.15(react@18.3.1)
|
||||
'@ant-design/antd-theme-variable': 1.0.0
|
||||
@@ -12702,7 +12702,7 @@ snapshots:
|
||||
antd-dayjs-webpack-plugin: 1.0.6(dayjs@1.11.20)
|
||||
axios: 0.27.2
|
||||
babel-plugin-import: 1.13.8
|
||||
babel-plugin-styled-components: 2.1.4(@babel/core@7.29.0)(styled-components@6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
babel-plugin-styled-components: 2.1.4(@babel/core@7.23.6)(styled-components@6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
dayjs: 1.11.20
|
||||
dva-core: 2.0.4(redux@4.2.1)
|
||||
dva-immer: 1.0.2(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
@@ -12732,7 +12732,7 @@ snapshots:
|
||||
- react-native
|
||||
- supports-color
|
||||
|
||||
'@umijs/plugins@4.6.51(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@umijs/plugins@4.6.51(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@ahooksjs/use-request': 2.8.15(react@18.3.1)
|
||||
'@ant-design/antd-theme-variable': 1.0.0
|
||||
@@ -12747,7 +12747,7 @@ snapshots:
|
||||
antd-dayjs-webpack-plugin: 1.0.6(dayjs@1.11.20)
|
||||
axios: 0.27.2
|
||||
babel-plugin-import: 1.13.8
|
||||
babel-plugin-styled-components: 2.1.4(@babel/core@7.29.0)(styled-components@6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
babel-plugin-styled-components: 2.1.4(@babel/core@7.23.6)(styled-components@6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
dayjs: 1.11.20
|
||||
dva-core: 2.0.4(redux@4.2.1)
|
||||
dva-immer: 1.0.2(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
@@ -12777,7 +12777,7 @@ snapshots:
|
||||
- react-native
|
||||
- supports-color
|
||||
|
||||
'@umijs/preset-umi@4.6.51(@types/node@25.6.2)(@types/react@18.3.28)(lightningcss@1.22.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))':
|
||||
'@umijs/preset-umi@4.6.51(@types/node@25.6.2)(@types/react@18.3.28)(lightningcss@1.22.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))':
|
||||
dependencies:
|
||||
'@iconify/utils': 2.1.1
|
||||
'@stagewise/toolbar': 0.6.2
|
||||
@@ -12787,7 +12787,7 @@ snapshots:
|
||||
'@umijs/bundler-esbuild': 4.6.51
|
||||
'@umijs/bundler-mako': 0.11.10(postcss@8.5.14)(sass@1.54.0)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/bundler-utils': 4.6.51
|
||||
'@umijs/bundler-utoopack': 4.6.51(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/bundler-utoopack': 4.6.51(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/bundler-vite': 4.6.51(@types/node@25.6.2)(lightningcss@1.22.1)(postcss@8.5.14)(rollup@3.30.0)(sass@1.54.0)(terser@5.48.0)
|
||||
'@umijs/bundler-webpack': 4.6.51(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/core': 4.6.51
|
||||
@@ -12870,13 +12870,13 @@ snapshots:
|
||||
react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react-router-dom: 6.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
|
||||
'@umijs/request-record@1.1.4(umi@4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))':
|
||||
'@umijs/request-record@1.1.4(umi@4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))':
|
||||
dependencies:
|
||||
chokidar: 3.6.0
|
||||
express: 4.22.1
|
||||
lodash: 4.18.1
|
||||
prettier: 2.8.8
|
||||
umi: 4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
umi: 4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -12892,13 +12892,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@umijs/test@4.6.51(@babel/core@7.29.0)':
|
||||
'@umijs/test@4.6.51(@babel/core@7.23.6)':
|
||||
dependencies:
|
||||
'@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.29.0)
|
||||
'@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.6)
|
||||
'@jest/types': 27.5.1
|
||||
'@umijs/bundler-utils': 4.6.51
|
||||
'@umijs/utils': 4.6.51
|
||||
babel-jest: 29.7.0(@babel/core@7.29.0)
|
||||
babel-jest: 29.7.0(@babel/core@7.23.6)
|
||||
esbuild: 0.21.4
|
||||
identity-obj-proxy: 3.0.0
|
||||
isomorphic-unfetch: 4.0.2
|
||||
@@ -13018,7 +13018,7 @@ snapshots:
|
||||
'@utoo/pack-win32-x64-msvc@1.4.3':
|
||||
optional: true
|
||||
|
||||
'@utoo/pack@1.4.3(less-loader@11.1.0(less@4.1.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))(less@4.1.3)(postcss@8.5.14)(resolve-url-loader@5.0.0)(sass-loader@13.2.0(sass@1.54.0)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))':
|
||||
'@utoo/pack@1.4.3(less-loader@11.1.0(less@4.1.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))(less@4.1.3)(postcss@8.5.14)(resolve-url-loader@5.0.0)(sass-loader@13.2.0(sass@1.54.0)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.22.5
|
||||
'@hono/node-server': 1.19.14(hono@4.12.18)
|
||||
@@ -13039,7 +13039,7 @@ snapshots:
|
||||
sass-loader: 13.2.0(sass@1.54.0)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
semver: 7.8.0
|
||||
send: 0.17.1
|
||||
styled-jsx: 5.1.7(@babel/core@7.29.0)(react@18.3.1)
|
||||
styled-jsx: 5.1.7(@babel/core@7.23.6)(react@18.3.1)
|
||||
ws: 8.20.0
|
||||
optionalDependencies:
|
||||
'@utoo/pack-darwin-arm64': 1.4.3
|
||||
@@ -13555,13 +13555,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
babel-jest@29.7.0(@babel/core@7.29.0):
|
||||
babel-jest@29.7.0(@babel/core@7.23.6):
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@jest/transform': 29.7.0
|
||||
'@types/babel__core': 7.20.5
|
||||
babel-plugin-istanbul: 6.1.1
|
||||
babel-preset-jest: 29.6.3(@babel/core@7.29.0)
|
||||
babel-preset-jest: 29.6.3(@babel/core@7.23.6)
|
||||
chalk: 4.1.2
|
||||
graceful-fs: 4.2.11
|
||||
slash: 3.0.0
|
||||
@@ -13601,9 +13601,9 @@ snapshots:
|
||||
cosmiconfig: 7.1.0
|
||||
resolve: 1.22.12
|
||||
|
||||
babel-plugin-named-asset-import@0.3.8(@babel/core@7.29.0):
|
||||
babel-plugin-named-asset-import@0.3.8(@babel/core@7.23.6):
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
|
||||
babel-plugin-react-compiler@0.0.0-experimental-c23de8d-20240515:
|
||||
dependencies:
|
||||
@@ -13615,11 +13615,11 @@ snapshots:
|
||||
zod: 3.25.76
|
||||
zod-validation-error: 2.1.0(zod@3.25.76)
|
||||
|
||||
babel-plugin-styled-components@2.1.4(@babel/core@7.29.0)(styled-components@6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
|
||||
babel-plugin-styled-components@2.1.4(@babel/core@7.23.6)(styled-components@6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
|
||||
dependencies:
|
||||
'@babel/helper-annotate-as-pure': 7.27.3
|
||||
'@babel/helper-module-imports': 7.28.6
|
||||
'@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.23.6)
|
||||
lodash: 4.18.1
|
||||
picomatch: 2.3.2
|
||||
styled-components: 6.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -13627,30 +13627,30 @@ snapshots:
|
||||
- '@babel/core'
|
||||
- supports-color
|
||||
|
||||
babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0):
|
||||
babel-preset-current-node-syntax@1.2.0(@babel/core@7.23.6):
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0)
|
||||
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0)
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.23.6)
|
||||
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.6)
|
||||
|
||||
babel-preset-jest@29.6.3(@babel/core@7.29.0):
|
||||
babel-preset-jest@29.6.3(@babel/core@7.23.6):
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
babel-plugin-jest-hoist: 29.6.3
|
||||
babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0)
|
||||
babel-preset-current-node-syntax: 1.2.0(@babel/core@7.23.6)
|
||||
|
||||
babel-runtime-jsx-plus@0.1.5: {}
|
||||
|
||||
@@ -16410,9 +16410,9 @@ snapshots:
|
||||
|
||||
jiti@2.7.0: {}
|
||||
|
||||
jotai@2.20.0(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@18.3.28)(react@18.3.1):
|
||||
jotai@2.20.0(@babel/core@7.23.6)(@babel/template@7.28.6)(@types/react@18.3.28)(react@18.3.1):
|
||||
optionalDependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
'@babel/template': 7.28.6
|
||||
'@types/react': 18.3.28
|
||||
react: 18.3.1
|
||||
@@ -19805,12 +19805,12 @@ snapshots:
|
||||
css-to-react-native: 3.2.0
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1):
|
||||
styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/core': 7.23.6
|
||||
|
||||
stylelint-config-recommended@7.0.0(stylelint@14.8.2):
|
||||
dependencies:
|
||||
@@ -20164,12 +20164,12 @@ snapshots:
|
||||
|
||||
ua-parser-js@0.7.41: {}
|
||||
|
||||
umi-presets-pro@2.0.3(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(chokidar@3.6.0)(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(umi@4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))):
|
||||
umi-presets-pro@2.0.3(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(chokidar@3.6.0)(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(umi@4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))):
|
||||
dependencies:
|
||||
'@alita/plugins': 3.5.5(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@alita/plugins': 3.5.5(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@umijs/max-plugin-openapi': 2.0.3(chokidar@3.6.0)(encoding@0.1.13)(typescript@5.9.3)
|
||||
'@umijs/plugins': 4.6.51(@babel/core@7.29.0)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@umijs/request-record': 1.1.4(umi@4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))
|
||||
'@umijs/plugins': 4.6.51(@babel/core@7.23.6)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(antd@6.3.7(date-fns@2.30.0)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(dva@2.5.0-beta.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(rc-field-form@2.7.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@umijs/request-record': 1.1.4(umi@4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)))
|
||||
swagger-ui-dist: 4.19.1
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
@@ -20193,17 +20193,17 @@ snapshots:
|
||||
isomorphic-fetch: 2.2.1
|
||||
qs: 6.15.1
|
||||
|
||||
umi@4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@8.35.0)(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)):
|
||||
umi@4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@8.35.0)(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@umijs/bundler-utils': 4.6.51
|
||||
'@umijs/bundler-webpack': 4.6.51(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/core': 4.6.51
|
||||
'@umijs/lint': 4.6.51(eslint@8.35.0)(stylelint@14.8.2)(typescript@5.9.3)
|
||||
'@umijs/preset-umi': 4.6.51(@types/node@25.6.2)(@types/react@18.3.28)(lightningcss@1.22.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/preset-umi': 4.6.51(@types/node@25.6.2)(@types/react@18.3.28)(lightningcss@1.22.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/renderer-react': 4.6.51(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@umijs/server': 4.6.51
|
||||
'@umijs/test': 4.6.51(@babel/core@7.29.0)
|
||||
'@umijs/test': 4.6.51(@babel/core@7.23.6)
|
||||
'@umijs/utils': 4.6.51
|
||||
prettier-plugin-organize-imports: 3.2.4(prettier@3.8.3)(typescript@5.9.3)
|
||||
prettier-plugin-packagejson: 2.4.3(prettier@3.8.3)
|
||||
@@ -20247,17 +20247,17 @@ snapshots:
|
||||
- webpack-hot-middleware
|
||||
- webpack-plugin-serve
|
||||
|
||||
umi@4.6.51(@babel/core@7.29.0)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)):
|
||||
umi@4.6.51(@babel/core@7.23.6)(@types/node@25.6.2)(@types/react@18.3.28)(eslint@9.39.4(jiti@2.7.0))(lightningcss@1.22.1)(prettier@3.8.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(stylelint@14.8.2)(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14)):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.6
|
||||
'@umijs/bundler-utils': 4.6.51
|
||||
'@umijs/bundler-webpack': 4.6.51(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/core': 4.6.51
|
||||
'@umijs/lint': 4.6.51(eslint@9.39.4(jiti@2.7.0))(stylelint@14.8.2)(typescript@5.9.3)
|
||||
'@umijs/preset-umi': 4.6.51(@types/node@25.6.2)(@types/react@18.3.28)(lightningcss@1.22.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.29.0)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/preset-umi': 4.6.51(@types/node@25.6.2)(@types/react@18.3.28)(lightningcss@1.22.1)(rollup@3.30.0)(sass@1.54.0)(styled-jsx@5.1.7(@babel/core@7.23.6)(react@18.3.1))(terser@5.48.0)(type-fest@0.20.2)(typescript@5.9.3)(webpack@5.106.2(lightningcss@1.22.1)(postcss@8.5.14))
|
||||
'@umijs/renderer-react': 4.6.51(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@umijs/server': 4.6.51
|
||||
'@umijs/test': 4.6.51(@babel/core@7.29.0)
|
||||
'@umijs/test': 4.6.51(@babel/core@7.23.6)
|
||||
'@umijs/utils': 4.6.51
|
||||
prettier-plugin-organize-imports: 3.2.4(prettier@3.8.3)(typescript@5.9.3)
|
||||
prettier-plugin-packagejson: 2.4.3(prettier@3.8.3)
|
||||
|
||||
+17
-85
@@ -3,9 +3,6 @@ import { GPUStackVersionAtom, UpdateCheckAtom, userAtom } from '@/atoms/user';
|
||||
import { setAtomStorage } from '@/atoms/utils';
|
||||
import { DEFAULT_ENTER_PAGE, GPUSTACK_API_BASE_URL } from '@/config/settings';
|
||||
import { COLOR_PRIMARY } from '@/config/theme/constants';
|
||||
import { queryClusterList } from '@/pages/cluster-management/apis';
|
||||
import { ProviderValueMap } from '@/pages/cluster-management/config';
|
||||
import { queryResourceEvents } from '@/pages/usage/apis/resource';
|
||||
import { getGPUStackPlugin } from '@/plugins';
|
||||
import { enterprisePluginReady } from '@/plugins/enterprise-ready';
|
||||
import { GPUStackPluginManager } from '@/plugins/manager';
|
||||
@@ -17,6 +14,10 @@ import {
|
||||
} from '@/services/profile/apis';
|
||||
import { fetchSystemConfig } from '@/services/system/query-system-config';
|
||||
import { isOnline } from '@/utils';
|
||||
import {
|
||||
markInitialStateProbed,
|
||||
probeAccessFlags
|
||||
} from '@/utils/access-probes';
|
||||
import { installTenantFetch } from '@/utils/install-fetch';
|
||||
import {
|
||||
IS_FIRST_LOGIN,
|
||||
@@ -41,80 +42,6 @@ const checkDefaultPage = async (userInfo: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
// Probes the caller's cluster list once so access predicates can gate
|
||||
// GPU Service (Kubernetes-only). Cheap (one list request) and never
|
||||
// blocks login — any failure just falls back to `undefined`, which
|
||||
// the predicate treats as "unknown / don't restrict beyond role".
|
||||
// The result is also mirrored into sessionStorage so access extensions
|
||||
// that run without the initialState argument can read it (e.g. to
|
||||
// override the admin shortcut in scopes where the menu shouldn't
|
||||
// show even for admins).
|
||||
const HAS_K8S_CLUSTER_KEY = 'hasKubernetesCluster';
|
||||
const probeHasKubernetesCluster = async (): Promise<boolean | undefined> => {
|
||||
try {
|
||||
const res = await queryClusterList(
|
||||
{ page: -1 },
|
||||
{
|
||||
skipErrorHandler: true
|
||||
}
|
||||
);
|
||||
const value = (res?.items ?? []).some(
|
||||
(c) => c?.provider === ProviderValueMap.Kubernetes
|
||||
);
|
||||
try {
|
||||
window.sessionStorage.setItem(HAS_K8S_CLUSTER_KEY, JSON.stringify(value));
|
||||
} catch {
|
||||
// sessionStorage may be unavailable (Safari private mode); the
|
||||
// access predicate already handles a missing value as "unknown".
|
||||
}
|
||||
return value;
|
||||
} catch (error) {
|
||||
console.error('probeHasKubernetesCluster error', error);
|
||||
try {
|
||||
window.sessionStorage.removeItem(HAS_K8S_CLUSTER_KEY);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// Probes whether the caller has ANY resource-usage events (GPU/CPU instance or
|
||||
// storage lifecycle). Used alongside the cluster probe so a user who has run
|
||||
// GPU instances still sees GPU Service / the full Usage page even if they
|
||||
// currently have no Kubernetes cluster. Mirrored into sessionStorage for the
|
||||
// access extensions; any failure → undefined ("unknown — don't restrict").
|
||||
const HAS_RESOURCE_EVENTS_KEY = 'hasResourceEvents';
|
||||
const probeHasResourceEvents = async (): Promise<boolean | undefined> => {
|
||||
try {
|
||||
// No date range = "ever"; scope is clamped to the caller server-side.
|
||||
const res = await queryResourceEvents(
|
||||
{ perPage: 1 },
|
||||
{
|
||||
skipErrorHandler: true
|
||||
}
|
||||
);
|
||||
const value = (res?.pagination?.total ?? 0) > 0;
|
||||
try {
|
||||
window.sessionStorage.setItem(
|
||||
HAS_RESOURCE_EVENTS_KEY,
|
||||
JSON.stringify(value)
|
||||
);
|
||||
} catch {
|
||||
// sessionStorage may be unavailable; predicate treats missing as unknown.
|
||||
}
|
||||
return value;
|
||||
} catch (error) {
|
||||
console.error('probeHasResourceEvents error', error);
|
||||
try {
|
||||
window.sessionStorage.removeItem(HAS_RESOURCE_EVENTS_KEY);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// runtime configuration
|
||||
export async function getInitialState(): Promise<{
|
||||
fetchUserInfo: () => Promise<Global.UserInfo>;
|
||||
@@ -235,19 +162,24 @@ export async function getInitialState(): Promise<{
|
||||
getAppVersionInfo();
|
||||
|
||||
if (![DEFAULT_ENTER_PAGE.login].includes(location.pathname)) {
|
||||
const [userInfo, hasKubernetesCluster, hasResourceEvents] =
|
||||
await Promise.all([
|
||||
fetchUserInfo(),
|
||||
probeHasKubernetesCluster(),
|
||||
probeHasResourceEvents()
|
||||
]);
|
||||
const [userInfo, accessFlags] = await Promise.all([
|
||||
fetchUserInfo(),
|
||||
probeAccessFlags()
|
||||
]);
|
||||
// Record that the probes ran for an authenticated user this page load
|
||||
// (the refresh path) so the layout doesn't re-probe. A failed
|
||||
// fetch (empty user — e.g. unauthenticated deep link that bounces to
|
||||
// login) is NOT marked: the user will log in via SPA afterwards and
|
||||
// the layout becomes responsible for probing.
|
||||
if (userInfo?.username) {
|
||||
markInitialStateProbed();
|
||||
}
|
||||
checkDefaultPage(userInfo);
|
||||
return {
|
||||
fetchUserInfo,
|
||||
currentUser: userInfo,
|
||||
pluginData,
|
||||
hasKubernetesCluster,
|
||||
hasResourceEvents
|
||||
...accessFlags
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
||||
+7
-2
@@ -638,10 +638,15 @@ body {
|
||||
inset: 53px auto auto 0 !important;
|
||||
border-radius: 0 0 var(--border-radius-base) var(--border-radius-base);
|
||||
border-top: none;
|
||||
max-height: 240px;
|
||||
min-height: 100px;
|
||||
.ant-cascader-menus {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
&.gpu-selector {
|
||||
.ant-cascader-menu {
|
||||
max-height: 400px;
|
||||
height: unset;
|
||||
}
|
||||
.ant-cascader-menu:last-child {
|
||||
flex: auto;
|
||||
|
||||
|
||||
+46
-1
@@ -12,6 +12,7 @@ import useUserSettings from '@/hooks/use-user-settings';
|
||||
import useUserSettingsStorage from '@/hooks/use-user-settings-storage';
|
||||
import useAddResource from '@/pages/dashboard/hooks/use-add-resource';
|
||||
import { logout } from '@/pages/login/apis';
|
||||
import { didInitialStateProbe, probeAccessFlags } from '@/utils/access-probes';
|
||||
import {
|
||||
readColumnSettings,
|
||||
readState,
|
||||
@@ -41,7 +42,7 @@ import {
|
||||
import { Button, ConfigProvider, Modal, theme } from 'antd';
|
||||
import { useAtom } from 'jotai';
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { PageContainerInner } from '../pages/_components/page-box';
|
||||
import Exception from './Exception';
|
||||
import './Layout.css';
|
||||
@@ -155,6 +156,50 @@ export default (props: any) => {
|
||||
|
||||
const { initialState, loading, setInitialState } = initialInfo;
|
||||
const access = useAccess();
|
||||
const probedForUserRef = useRef<string | null>(null);
|
||||
|
||||
// Backfill the access probes (cluster / resource-events) once we're in
|
||||
// the authenticated shell. `getInitialState` runs only once at app
|
||||
// boot and can't probe on the login page (no session => 401), so after
|
||||
// a first login the flags arrive here as `undefined` — which the
|
||||
// access predicate treats as "don't restrict", flashing GPU Service /
|
||||
// the full Usage page on until a manual refresh. This layout mounts
|
||||
// only post-auth (login is `layout:false`) and on every entry, so it's
|
||||
// the reliable place to resolve them.
|
||||
//
|
||||
// The effect is keyed on the user IDENTITY, not on the flag values —
|
||||
// gating on the flags is what made this fragile (on a refresh
|
||||
// `getInitialState` commits `currentUser` and the flags in the same
|
||||
// update, so a flag-gated effect sees them already-known and never
|
||||
// fires). Whether to actually hit the network is decided by the
|
||||
// module-scoped `didInitialStateProbe()` marker, which is true only
|
||||
// when `getInitialState` already probed for an authenticated user this
|
||||
// page load (the refresh path) — so we skip the duplicate request there
|
||||
// but still probe on the SPA-login path. Keying on identity also
|
||||
// re-probes correctly if the signed-in user changes.
|
||||
const currentUser = initialState?.currentUser;
|
||||
const username = currentUser?.username;
|
||||
|
||||
useEffect(() => {
|
||||
if (!username || !setInitialState) {
|
||||
return;
|
||||
}
|
||||
if (probedForUserRef.current === username) {
|
||||
return;
|
||||
}
|
||||
probedForUserRef.current = username;
|
||||
// The refresh path already resolved the flags inside `getInitialState`
|
||||
// for this user — don't issue a duplicate probe.
|
||||
if (didInitialStateProbe()) {
|
||||
return;
|
||||
}
|
||||
probeAccessFlags().then((accessFlags) => {
|
||||
setInitialState((prev: any) => ({
|
||||
...prev,
|
||||
...accessFlags
|
||||
}));
|
||||
});
|
||||
}, [username, setInitialState]);
|
||||
|
||||
const userConfig = {
|
||||
title: '',
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import { IconFont } from '@gpustack/core-ui';
|
||||
import { Collapse, CollapseProps } from 'antd';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const CollapseInner = styled(Collapse)`
|
||||
.ant-collapse-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px !important;
|
||||
padding-inline: 5px !important;
|
||||
padding-block: 8px !important;
|
||||
border-radius: var(--border-radius-base) !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 600 !important;
|
||||
&:hover {
|
||||
background-color: var(--ant-color-fill-tertiary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-collapse-body {
|
||||
padding-inline: 0 !important;
|
||||
padding-block: 0 !important;
|
||||
}
|
||||
.ant-collapse-header-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
const CollapsePanel: React.FC<{
|
||||
items: CollapseProps['items'];
|
||||
activeKey: string | string[];
|
||||
accordion?: boolean;
|
||||
defaultActiveKey?: string | string[];
|
||||
onChange?: (key: string | string[]) => void;
|
||||
styles?: Record<string, React.CSSProperties>;
|
||||
}> = ({ items, activeKey, accordion, defaultActiveKey, onChange, styles }) => {
|
||||
return (
|
||||
<CollapseInner
|
||||
expandIconPlacement="start"
|
||||
bordered={false}
|
||||
ghost
|
||||
accordion={accordion}
|
||||
activeKey={activeKey}
|
||||
defaultActiveKey={defaultActiveKey}
|
||||
onChange={onChange}
|
||||
destroyOnHidden={false}
|
||||
styles={{
|
||||
...styles,
|
||||
header: {
|
||||
backgroundColor: 'var(--ant-collapse-header-bg)'
|
||||
}
|
||||
}}
|
||||
expandIcon={({ isActive }) => (
|
||||
<IconFont
|
||||
type="icon-down"
|
||||
rotate={isActive ? 0 : -90}
|
||||
style={{ fontSize: '14px' }}
|
||||
></IconFont>
|
||||
)}
|
||||
items={items}
|
||||
></CollapseInner>
|
||||
);
|
||||
};
|
||||
|
||||
export default CollapsePanel;
|
||||
@@ -1,250 +0,0 @@
|
||||
import {
|
||||
readColumnSettings,
|
||||
writeColumnSettings
|
||||
} from '@/utils/localstore/index';
|
||||
import { SettingOutlined } from '@ant-design/icons';
|
||||
import { OverlayScroller } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Checkbox, Col, Popover, Row, Tooltip } from 'antd';
|
||||
import React, { useEffect } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Container = styled.div`
|
||||
padding: 8px 12px;
|
||||
padding-right: 4px;
|
||||
.title {
|
||||
font-weight: 500;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.btn-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 12px;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
`;
|
||||
|
||||
const Title = styled.div`
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 4px;
|
||||
`;
|
||||
|
||||
const LabelWrapper = styled.span`
|
||||
color: var(--ant-color-text-secondary);
|
||||
> span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: var(--ant-color-text-secondary);
|
||||
.sub-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ColumnSettings: React.FC<{
|
||||
width?: number;
|
||||
fixedColumns?: string[];
|
||||
tableName: string;
|
||||
contentHeight: number;
|
||||
columns: {
|
||||
title: React.ReactNode;
|
||||
dataIndex?: string;
|
||||
children?: { title: React.ReactNode; dataIndex?: string }[];
|
||||
}[];
|
||||
selectedColumns?: string[];
|
||||
defaultSelectedColumns?: string[];
|
||||
grouped?: boolean;
|
||||
onReset?: () => void;
|
||||
onChange?: (selectedColumns: string[]) => void;
|
||||
}> = (props) => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
tableName,
|
||||
contentHeight,
|
||||
width = 420,
|
||||
columns,
|
||||
selectedColumns,
|
||||
defaultSelectedColumns,
|
||||
grouped,
|
||||
onReset,
|
||||
onChange,
|
||||
fixedColumns
|
||||
} = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [innerSelectedColumns, setInnerSelectedColumns] = React.useState<
|
||||
string[]
|
||||
>(defaultSelectedColumns || []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (open) {
|
||||
setInnerSelectedColumns(selectedColumns ?? defaultSelectedColumns ?? []);
|
||||
}
|
||||
}, [open, selectedColumns, defaultSelectedColumns]);
|
||||
|
||||
const handleToggle = () => {
|
||||
setOpen(!open);
|
||||
};
|
||||
|
||||
const handleDraftChange = (columns: string[]) => {
|
||||
setInnerSelectedColumns(columns);
|
||||
};
|
||||
|
||||
const handleSelectAll = () => {
|
||||
if (grouped) {
|
||||
const allCols: string[] = [];
|
||||
columns.forEach((group) => {
|
||||
group.children?.forEach((col) => {
|
||||
if (col.dataIndex) {
|
||||
allCols.push(col.dataIndex);
|
||||
}
|
||||
});
|
||||
});
|
||||
handleDraftChange(allCols);
|
||||
} else {
|
||||
const allCols = columns
|
||||
.map((col) => col.dataIndex)
|
||||
.filter((dataIndex): dataIndex is string => Boolean(dataIndex));
|
||||
handleDraftChange(allCols);
|
||||
}
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
setOpen(false);
|
||||
writeColumnSettings(tableName, innerSelectedColumns);
|
||||
onChange?.(innerSelectedColumns);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
const resetCols = defaultSelectedColumns ?? [];
|
||||
writeColumnSettings(tableName, resetCols);
|
||||
onChange?.(resetCols);
|
||||
setInnerSelectedColumns(resetCols);
|
||||
onReset?.();
|
||||
};
|
||||
|
||||
const handleOpenChange = (isOpen: boolean) => {
|
||||
setOpen(isOpen);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const initColumns = async () => {
|
||||
const stored = await readColumnSettings(tableName);
|
||||
if (stored && stored.length > 0) {
|
||||
setInnerSelectedColumns(stored);
|
||||
onChange?.(stored);
|
||||
} else {
|
||||
setInnerSelectedColumns(defaultSelectedColumns || []);
|
||||
}
|
||||
};
|
||||
initColumns();
|
||||
}, []);
|
||||
|
||||
const contentRender = () => {
|
||||
return (
|
||||
<Container>
|
||||
{!grouped && (
|
||||
<div className="title">
|
||||
{intl.formatMessage({ id: 'benchmark.table.columnSettings' })}
|
||||
</div>
|
||||
)}
|
||||
<OverlayScroller
|
||||
maxHeight={contentHeight}
|
||||
styles={{
|
||||
wrapper: {
|
||||
paddingInlineStart: 0
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Checkbox.Group
|
||||
value={innerSelectedColumns}
|
||||
onChange={handleDraftChange}
|
||||
>
|
||||
<>
|
||||
{grouped ? (
|
||||
columns.map((row, index) => (
|
||||
<div key={index}>
|
||||
<Title>{row.title}</Title>
|
||||
<Row>
|
||||
{row.children?.map((col) => (
|
||||
<Col key={col.dataIndex} span={12}>
|
||||
<Checkbox
|
||||
disabled={fixedColumns?.includes(
|
||||
col.dataIndex || ''
|
||||
)}
|
||||
value={col.dataIndex}
|
||||
style={{ marginBottom: 8 }}
|
||||
>
|
||||
<LabelWrapper>{col.title}</LabelWrapper>
|
||||
</Checkbox>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<Row>
|
||||
{columns.map((col) => (
|
||||
<Col key={col.dataIndex} span={12}>
|
||||
<Checkbox
|
||||
disabled={fixedColumns?.includes(col.dataIndex || '')}
|
||||
value={col.dataIndex}
|
||||
style={{ marginBottom: 8 }}
|
||||
>
|
||||
<LabelWrapper>{col.title}</LabelWrapper>
|
||||
</Checkbox>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
)}
|
||||
</>
|
||||
</Checkbox.Group>
|
||||
</OverlayScroller>
|
||||
|
||||
<div className="btn-wrapper">
|
||||
<Button size="middle" onClick={handleReset}>
|
||||
{intl.formatMessage({ id: 'common.button.resetdefault' })}
|
||||
</Button>
|
||||
<div className="buttons">
|
||||
<Button size="middle" type="primary" onClick={handleSelectAll}>
|
||||
{intl.formatMessage({ id: 'common.checkbox.all' })}
|
||||
</Button>
|
||||
<Button size="middle" type="primary" onClick={handleConfirm}>
|
||||
{intl.formatMessage({ id: 'common.button.save' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover
|
||||
open={open}
|
||||
onOpenChange={handleOpenChange}
|
||||
trigger={'click'}
|
||||
arrow={false}
|
||||
placement="bottomRight"
|
||||
content={contentRender()}
|
||||
styles={{
|
||||
root: {
|
||||
width: width
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
title={intl.formatMessage({ id: 'benchmark.table.columnSettings' })}
|
||||
>
|
||||
<Button onClick={handleToggle} icon={<SettingOutlined />}></Button>
|
||||
</Tooltip>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColumnSettings;
|
||||
@@ -1,99 +0,0 @@
|
||||
import { useOverlayScroller } from '@gpustack/core-ui';
|
||||
import React, { useCallback } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { WrapperContext } from './use-wrapper-context';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const ContentWrapper = styled.div`
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
const Footer = styled.div`
|
||||
padding-block: 0;
|
||||
background-color: var(--ant-color-bg-elevated);
|
||||
`;
|
||||
|
||||
interface ColumnWrapperProps {
|
||||
children: React.ReactNode;
|
||||
footer?: React.ReactNode;
|
||||
maxHeight?: string | number;
|
||||
paddingBottom?: number;
|
||||
styles?: {
|
||||
wrapper?: React.CSSProperties;
|
||||
container?: React.CSSProperties;
|
||||
};
|
||||
}
|
||||
|
||||
const ColumnWrapper: React.FC<ColumnWrapperProps> = ({
|
||||
children,
|
||||
footer,
|
||||
maxHeight,
|
||||
styles = {}
|
||||
}) => {
|
||||
const scroller = React.useRef<any>(null);
|
||||
const footerRef = React.useRef<HTMLDivElement>(null);
|
||||
const contentRef = React.useRef<HTMLDivElement>(null);
|
||||
const {
|
||||
initialize,
|
||||
instance,
|
||||
scrollEventElement,
|
||||
scrollToBottom,
|
||||
scrollToTarget,
|
||||
getScrollElementScrollableHeight
|
||||
} = useOverlayScroller({
|
||||
options: {
|
||||
scrollbars: {
|
||||
autoHide: 'move'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (scroller.current) {
|
||||
initialize(scroller.current);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const setContentPaddingBottom = useCallback((padding: number) => {
|
||||
contentRef.current!.style.paddingBottom = `${padding}px`;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<WrapperContext.Provider
|
||||
value={{
|
||||
scroller: scroller,
|
||||
osInstance: instance,
|
||||
scrollEventElement,
|
||||
getScrollElementScrollableHeight,
|
||||
scrollToBottom,
|
||||
scrollToTarget,
|
||||
setSScrollContentPaddingBottom: setContentPaddingBottom
|
||||
}}
|
||||
>
|
||||
<Wrapper style={{ height: maxHeight || '100%', ...styles.wrapper }}>
|
||||
<ContentWrapper
|
||||
ref={scroller}
|
||||
style={{
|
||||
padding: '16px 24px',
|
||||
...styles.container
|
||||
}}
|
||||
>
|
||||
<div ref={contentRef}>{children}</div>
|
||||
</ContentWrapper>
|
||||
{footer && <Footer ref={footerRef}>{footer}</Footer>}
|
||||
</Wrapper>
|
||||
</WrapperContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColumnWrapper;
|
||||
@@ -1,28 +0,0 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
interface WrapperContextProps {
|
||||
osInstance?: any;
|
||||
scroller?: any;
|
||||
scrollEventElement?: any;
|
||||
scrollToBottom?: () => void;
|
||||
scrollToTop?: () => void;
|
||||
getScrollElementScrollableHeight?: () => {
|
||||
scrollHeight: number;
|
||||
scrollTop: number;
|
||||
};
|
||||
scrollToTarget?: (target: any, offset?: number) => void;
|
||||
getScrollElement?: () => HTMLElement | null;
|
||||
setSScrollContentPaddingBottom?: (padding: number) => void;
|
||||
}
|
||||
|
||||
export const WrapperContext = createContext<WrapperContextProps>(
|
||||
{} as WrapperContextProps
|
||||
);
|
||||
|
||||
export const useWrapperContext = () => {
|
||||
const context = useContext(WrapperContext);
|
||||
if (!context) {
|
||||
throw new Error('useWrapperContext must be used within a WrapperProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -1,155 +0,0 @@
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { OverlayScroller } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Form } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import React, { forwardRef, useImperativeHandle } from 'react';
|
||||
import filterFormCss from '../styles/filter-form.less';
|
||||
|
||||
const FilterForm: React.FC<
|
||||
React.PropsWithChildren & {
|
||||
ref?: any;
|
||||
width?: number;
|
||||
contentHeight?: number | string;
|
||||
initialValues?: any;
|
||||
hasFilters?: boolean;
|
||||
open?: boolean;
|
||||
onClear?: () => void;
|
||||
onClose?: () => void;
|
||||
onValuesChange?: (ChangeValues: any, allValues: any) => void;
|
||||
styles?: {
|
||||
container?: React.CSSProperties;
|
||||
wrapper?: React.CSSProperties;
|
||||
};
|
||||
}
|
||||
> = forwardRef(
|
||||
(
|
||||
{
|
||||
children,
|
||||
open,
|
||||
width = 300,
|
||||
contentHeight = 400,
|
||||
initialValues = {},
|
||||
styles,
|
||||
onClose,
|
||||
onClear,
|
||||
onValuesChange
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const intl = useIntl();
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleOnReset = () => {
|
||||
form.resetFields(Object.keys(initialValues));
|
||||
form.resetFields();
|
||||
onValuesChange?.({}, form.getFieldsValue());
|
||||
};
|
||||
|
||||
const handleOnClose = () => {
|
||||
onClose?.();
|
||||
};
|
||||
|
||||
const handleOnValuesChange = (changedValues: any, allValues: any) => {
|
||||
onValuesChange?.(changedValues, allValues);
|
||||
};
|
||||
|
||||
const handleOnClear = () => {
|
||||
handleOnReset();
|
||||
};
|
||||
|
||||
const filtersCount = Object.values(form.getFieldsValue()).filter(
|
||||
(value) => value !== undefined && value !== null && value !== ''
|
||||
).length;
|
||||
|
||||
const renderFooter = () => {
|
||||
return (
|
||||
<div className={filterFormCss['btn-wrapper']}>
|
||||
<Button size="middle" onClick={handleOnReset}>
|
||||
{intl.formatMessage({ id: 'common.button.reset' })}
|
||||
</Button>
|
||||
<div className={filterFormCss.buttons}>
|
||||
<Button size="middle" type="primary" onClick={handleOnClose}>
|
||||
{intl.formatMessage({ id: 'common.button.close' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
form,
|
||||
reset: handleOnReset,
|
||||
getValues: () => form.getFieldsValue(),
|
||||
setValues: (values: any) => form.setFieldsValue(values)
|
||||
}));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(filterFormCss.wrapper, {
|
||||
[filterFormCss.show]: open
|
||||
})}
|
||||
style={{
|
||||
width: open ? width : 0,
|
||||
height: contentHeight,
|
||||
...styles?.wrapper
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{ width: width, ...styles?.container }}
|
||||
className={filterFormCss.container}
|
||||
>
|
||||
<div className={filterFormCss.title}>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
color: 'var(--ant-color-text-tertiary)'
|
||||
}}
|
||||
>
|
||||
{intl.formatMessage({ id: 'common.filter.label' })}
|
||||
</span>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<CloseOutlined />}
|
||||
onClick={handleOnClose}
|
||||
type="text"
|
||||
style={{
|
||||
color: 'var(--ant-color-text-secondary)'
|
||||
}}
|
||||
></Button>
|
||||
</div>
|
||||
<OverlayScroller
|
||||
maxHeight={contentHeight}
|
||||
styles={{
|
||||
wrapper: {
|
||||
paddingInline: 8
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Form
|
||||
onValuesChange={handleOnValuesChange}
|
||||
initialValues={initialValues}
|
||||
form={form}
|
||||
layout="vertical"
|
||||
styles={{
|
||||
label: {
|
||||
lineHeight: 1,
|
||||
height: 'auto',
|
||||
marginBottom: 8,
|
||||
fontWeight: 500
|
||||
},
|
||||
content: {
|
||||
minHeight: 0
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Form>
|
||||
</OverlayScroller>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default FilterForm;
|
||||
@@ -1,90 +0,0 @@
|
||||
import { ColumnWrapper, GSDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import type { DrawerProps } from 'antd';
|
||||
import { Tag } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const ModalFooterStyle = {
|
||||
padding: '16px 24px 8px',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end'
|
||||
};
|
||||
|
||||
type AddModalProps = {
|
||||
title: React.ReactNode;
|
||||
open: boolean;
|
||||
onCancel?: () => void;
|
||||
children?: React.ReactNode;
|
||||
onSubmit?: () => void;
|
||||
width?: number | string;
|
||||
footer?: React.ReactNode;
|
||||
subTitle?: React.ReactNode;
|
||||
push?: DrawerProps['push'];
|
||||
};
|
||||
const FormDrawer: React.FC<AddModalProps> = ({
|
||||
title,
|
||||
open,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
children,
|
||||
width = 600,
|
||||
subTitle,
|
||||
footer,
|
||||
push
|
||||
}) => {
|
||||
return (
|
||||
<GSDrawer
|
||||
title={
|
||||
<>
|
||||
{title}
|
||||
{subTitle && (
|
||||
<Tag
|
||||
variant="outlined"
|
||||
style={{
|
||||
fontSize: 12,
|
||||
fontWeight: 400,
|
||||
marginLeft: 8,
|
||||
borderRadius: 4,
|
||||
borderColor: 'var(--ant-color-border-secondary)',
|
||||
color: 'var(--ant-color-text-secondary)'
|
||||
}}
|
||||
>
|
||||
{subTitle}
|
||||
</Tag>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
open={open}
|
||||
onClose={onCancel}
|
||||
destroyOnHidden={true}
|
||||
closeIcon={false}
|
||||
mask={{
|
||||
closable: false
|
||||
}}
|
||||
keyboard={false}
|
||||
push={push}
|
||||
styles={{
|
||||
wrapper: { width }
|
||||
}}
|
||||
footer={false}
|
||||
>
|
||||
<ColumnWrapper
|
||||
styles={{
|
||||
container: { paddingBlock: 0 }
|
||||
}}
|
||||
footer={
|
||||
footer ?? (
|
||||
<ModalFooter
|
||||
onOk={onSubmit}
|
||||
onCancel={onCancel}
|
||||
style={ModalFooterStyle}
|
||||
></ModalFooter>
|
||||
)
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</ColumnWrapper>
|
||||
</GSDrawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormDrawer;
|
||||
@@ -1,81 +0,0 @@
|
||||
.mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1004;
|
||||
height: 100%;
|
||||
background-color: var(--ant-color-bg-mask);
|
||||
opacity: 0;
|
||||
transition: opacity var(--ant-motion-duration-slow)
|
||||
var(--ant-motion-ease-in-out);
|
||||
}
|
||||
|
||||
.maskOpen {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
z-index: 1005;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: var(--ant-color-bg-elevated);
|
||||
border-radius: var(--ant-border-radius-lg) 0 0 var(--ant-border-radius-lg);
|
||||
box-shadow:
|
||||
-6px 0 16px 0 rgb(0 0 0 / 8%),
|
||||
-3px 0 6px -4px rgb(0 0 0 / 12%),
|
||||
-9px 0 28px 8px rgb(0 0 0 / 5%);
|
||||
transform: translateX(100%);
|
||||
transition: transform var(--ant-motion-duration-slow)
|
||||
var(--ant-motion-ease-in-out);
|
||||
}
|
||||
|
||||
.overlayOpen {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-height: 56px;
|
||||
padding: var(--ant-padding) var(--ant-padding-lg);
|
||||
border-bottom: 1px solid var(--ant-color-split);
|
||||
color: var(--ant-color-text);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
margin-left: 8px;
|
||||
border-color: var(--ant-color-border-secondary);
|
||||
border-radius: 4px;
|
||||
color: var(--ant-color-text-secondary);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-block: 16px;
|
||||
flex: 1;
|
||||
height: calc(100vh - 57px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 16px 24px 8px;
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import { ColumnWrapper, IconFont } from '@gpustack/core-ui';
|
||||
import { Button, Tag } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import styles from './form-overlay-view.module.less';
|
||||
|
||||
type FormOverlayViewProps = {
|
||||
title: React.ReactNode;
|
||||
open: boolean;
|
||||
onCancel?: () => void;
|
||||
children?: React.ReactNode;
|
||||
onSubmit?: () => void;
|
||||
footer?: React.ReactNode;
|
||||
subTitle?: React.ReactNode;
|
||||
width?: number | string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
maskClosable?: boolean;
|
||||
getContainer?: () => HTMLElement | null | undefined;
|
||||
};
|
||||
|
||||
const FormOverlayView: React.FC<FormOverlayViewProps> = ({
|
||||
title,
|
||||
open,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
children,
|
||||
subTitle,
|
||||
footer,
|
||||
width = 600,
|
||||
className,
|
||||
style,
|
||||
maskClosable = false,
|
||||
getContainer
|
||||
}) => {
|
||||
const [container, setContainer] = React.useState<HTMLElement | null>(null);
|
||||
const [mounted, setMounted] = React.useState(false);
|
||||
const [active, setActive] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (open) {
|
||||
setContainer(getContainer?.() ?? null);
|
||||
setMounted(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setActive(false);
|
||||
}, [getContainer, open]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!mounted || !container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = requestAnimationFrame(() => setActive(true));
|
||||
return () => cancelAnimationFrame(id);
|
||||
}, [mounted, container]);
|
||||
|
||||
const handleTransitionEnd = (e: React.TransitionEvent<HTMLDivElement>) => {
|
||||
if (e.target !== e.currentTarget || e.propertyName !== 'transform') {
|
||||
return;
|
||||
}
|
||||
if (!open && !active) {
|
||||
setMounted(false);
|
||||
setContainer(null);
|
||||
}
|
||||
};
|
||||
|
||||
if (!mounted || !container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createPortal(
|
||||
<>
|
||||
<div
|
||||
className={classNames(styles.mask, { [styles.maskOpen]: active })}
|
||||
onClick={maskClosable ? onCancel : undefined}
|
||||
/>
|
||||
<div
|
||||
className={classNames(
|
||||
styles.overlay,
|
||||
{ [styles.overlayOpen]: active },
|
||||
className
|
||||
)}
|
||||
style={{ width, ...style }}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
onTransitionEnd={handleTransitionEnd}
|
||||
>
|
||||
<div className={styles.header}>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
style={{ fontWeight: 600, fontSize: 16 }}
|
||||
icon={<IconFont type="icon-down2" rotate={90} />}
|
||||
onClick={onCancel}
|
||||
/>
|
||||
<div className={styles.title}>
|
||||
{title}
|
||||
{subTitle && (
|
||||
<Tag variant="outlined" className={styles.subTitle}>
|
||||
{subTitle}
|
||||
</Tag>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<ColumnWrapper
|
||||
styles={{
|
||||
container: { paddingBlock: 16 }
|
||||
}}
|
||||
footer={footer}
|
||||
>
|
||||
{children}
|
||||
</ColumnWrapper>
|
||||
</div>
|
||||
</>,
|
||||
container
|
||||
);
|
||||
};
|
||||
|
||||
export default FormOverlayView;
|
||||
File diff suppressed because one or more lines are too long
@@ -1,26 +0,0 @@
|
||||
import { update } from 'jdenticon';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
interface IdenticonProps {
|
||||
value: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
const Identicon: React.FC<IdenticonProps> = ({
|
||||
value = 'test',
|
||||
size = 28
|
||||
}: IdenticonProps) => {
|
||||
const icon = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
update(icon.current, value);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<svg data-jdenticon-value={value} height={size} ref={icon} width={size} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Identicon;
|
||||
@@ -1,68 +0,0 @@
|
||||
import {
|
||||
digitReg,
|
||||
lowercaseReg,
|
||||
specialCharacterReg,
|
||||
uppercaseReg
|
||||
} from '@/config';
|
||||
import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Space } from 'antd';
|
||||
|
||||
const PasswordValidate: React.FC<{ value: string }> = ({ value = '' }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const renderIcon = ({ valid, text }: { valid: boolean; text: string }) => {
|
||||
return (
|
||||
<>
|
||||
{valid ? (
|
||||
<CheckCircleFilled style={{ color: 'green' }} />
|
||||
) : (
|
||||
<CloseCircleFilled style={{ color: 'red' }} />
|
||||
)}
|
||||
<span
|
||||
className="m-l-5"
|
||||
style={{ color: 'var(--ant-color-text-description)' }}
|
||||
>
|
||||
{text}
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<Space direction="vertical" style={{ paddingTop: '10px' }}>
|
||||
<span>
|
||||
{renderIcon({
|
||||
valid: uppercaseReg.test(value),
|
||||
text: intl.formatMessage({ id: 'users.password.uppcase' })
|
||||
})}
|
||||
</span>
|
||||
<span>
|
||||
{renderIcon({
|
||||
valid: lowercaseReg.test(value),
|
||||
text: intl.formatMessage({ id: 'users.password.lowercase' })
|
||||
})}
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{renderIcon({
|
||||
valid: digitReg.test(value),
|
||||
text: intl.formatMessage({ id: 'users.password.number' })
|
||||
})}
|
||||
</span>
|
||||
<span>
|
||||
{renderIcon({
|
||||
valid: value.length >= 6 && value.length <= 12,
|
||||
text: intl.formatMessage({ id: 'users.password.length' })
|
||||
})}
|
||||
</span>
|
||||
<span>
|
||||
{renderIcon({
|
||||
valid: specialCharacterReg.test(value),
|
||||
text: intl.formatMessage({ id: 'users.password.special' })
|
||||
})}
|
||||
</span>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
export default PasswordValidate;
|
||||
@@ -1,60 +0,0 @@
|
||||
import { AutoTooltip } from '@gpustack/core-ui';
|
||||
import React from 'react';
|
||||
import pillButtonCss from './styles.less';
|
||||
type Option = {
|
||||
label: string;
|
||||
value: string | number | null;
|
||||
icon?: React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
value?: string | number;
|
||||
onChange?: (value: string | number | undefined | null) => void;
|
||||
options: Option[];
|
||||
disabled?: boolean;
|
||||
variant?: 'filled' | 'outlined' | 'solid';
|
||||
};
|
||||
|
||||
const PillButtonGroup: React.FC<Props> = ({
|
||||
value,
|
||||
onChange,
|
||||
options,
|
||||
disabled,
|
||||
variant = 'outlined'
|
||||
}) => {
|
||||
return (
|
||||
<div className={pillButtonCss['wrapper']}>
|
||||
{options.map((item) => {
|
||||
const active = value === item.value;
|
||||
|
||||
return (
|
||||
<AutoTooltip
|
||||
ghost
|
||||
title={item.label}
|
||||
key={item.value}
|
||||
maxWidth={'100%'}
|
||||
>
|
||||
<span
|
||||
className={`${pillButtonCss['pill-item']} ${active ? pillButtonCss['active'] : ''}`}
|
||||
key={item.value}
|
||||
color="default"
|
||||
onClick={() => {
|
||||
if (item.value !== value) {
|
||||
onChange?.(item.value);
|
||||
}
|
||||
if (item.value === value) {
|
||||
onChange?.(undefined);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.icon}
|
||||
{item.label}
|
||||
</span>
|
||||
</AutoTooltip>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PillButtonGroup;
|
||||
@@ -1,31 +0,0 @@
|
||||
.pill-item {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
border-radius: var(--ant-border-radius);
|
||||
background-color: var(--ant-color-fill-tertiary);
|
||||
color: var(--ant-color-text-secondary);
|
||||
padding: 0 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.active {
|
||||
background-color: var(--ant-color-fill);
|
||||
color: var(--ant-color-text);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&:not(.active):hover {
|
||||
background-color: var(--ant-color-fill-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
import { SegmentLine } from '@gpustack/core-ui';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import _ from 'lodash';
|
||||
import React, { forwardRef, useImperativeHandle } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import useFieldScroll from './use-field-scroll';
|
||||
|
||||
const SegmentedHeader = styled.div<{ $top?: number }>`
|
||||
position: sticky;
|
||||
top: ${(props) => props.$top || 0}px;
|
||||
z-index: 10;
|
||||
margin-bottom: 16px;
|
||||
border-bottom: 1px solid var(--ant-color-split);
|
||||
background-color: var(--ant-color-bg-elevated);
|
||||
`;
|
||||
|
||||
/**
|
||||
* ScrollSpyTabs component
|
||||
* defaultTarget: The default active target tab
|
||||
* segmentedTop: { // Mostlty, It's always a constants.
|
||||
* top: number; // The top offset for the sticky header
|
||||
* offsetTop: number; // The offset top for the target
|
||||
* }
|
||||
* getScrollElementScrollableHeight: function to get the scrollable height of the scroll element
|
||||
* segmentOptions.field: The target data-field={segmentOptions.field} to scroll to
|
||||
* activeKey: The current active keys for collapsible sections
|
||||
* setActiveKey: The function to set active keys for collapsible sections
|
||||
*/
|
||||
interface ScrollSpyTabsProps {
|
||||
ref?: any;
|
||||
children?: React.ReactNode;
|
||||
defaultTarget?: string;
|
||||
segmentedTop: {
|
||||
top: number;
|
||||
offsetTop: number;
|
||||
};
|
||||
activeKey: string[];
|
||||
setActiveKey: (keys: string[]) => void;
|
||||
getScrollElementScrollableHeight?: () => {
|
||||
scrollHeight: number;
|
||||
scrollTop: number;
|
||||
};
|
||||
segmentOptions: {
|
||||
label: string;
|
||||
value: string;
|
||||
icon?: React.ReactNode;
|
||||
field: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
const ScrollSpyTabs: React.FC<ScrollSpyTabsProps> = forwardRef(
|
||||
(
|
||||
{
|
||||
getScrollElementScrollableHeight,
|
||||
segmentedTop,
|
||||
segmentOptions,
|
||||
defaultTarget,
|
||||
activeKey,
|
||||
setActiveKey,
|
||||
children
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [target, setTarget] = React.useState<string>(
|
||||
defaultTarget || segmentOptions[0]?.value || ''
|
||||
);
|
||||
|
||||
const { scrollToSegment, holderHeight } = useFieldScroll({
|
||||
activeKey,
|
||||
setActiveKey,
|
||||
segmentOptions,
|
||||
segmentedTop: segmentedTop,
|
||||
getScrollElementScrollableHeight: getScrollElementScrollableHeight
|
||||
});
|
||||
|
||||
const throttleScrollToSegment = useMemoizedFn(
|
||||
_.throttle(
|
||||
async (val: string) => {
|
||||
setTarget(val);
|
||||
scrollToSegment(val, { offsetTop: segmentedTop.offsetTop });
|
||||
},
|
||||
500,
|
||||
{ trailing: true }
|
||||
)
|
||||
);
|
||||
|
||||
const handleTargetChange = async (val: any) => {
|
||||
throttleScrollToSegment(val);
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleTargetChange
|
||||
}));
|
||||
|
||||
return (
|
||||
<div>
|
||||
{segmentOptions.length > 0 && (
|
||||
<SegmentedHeader $top={segmentedTop.top}>
|
||||
<SegmentLine
|
||||
theme={'light'}
|
||||
defaultValue={target}
|
||||
value={target}
|
||||
onChange={handleTargetChange}
|
||||
options={segmentOptions}
|
||||
/>
|
||||
</SegmentedHeader>
|
||||
)}
|
||||
{children}
|
||||
<div className="holder" style={{ height: holderHeight }}></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ScrollSpyTabs;
|
||||
@@ -1,118 +0,0 @@
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
interface ScrollOptions {
|
||||
wait?: number;
|
||||
behavior?: 'smooth' | 'auto';
|
||||
block?: 'start' | 'end' | 'center';
|
||||
offsetTop?: number;
|
||||
}
|
||||
|
||||
export default function useScrollAfterExpand({
|
||||
activeKey,
|
||||
setActiveKey,
|
||||
segmentOptions,
|
||||
defaultWait = 300,
|
||||
segmentedTop = { top: 0, offsetTop: 96 },
|
||||
getScrollElementScrollableHeight
|
||||
}: {
|
||||
activeKey: string[];
|
||||
setActiveKey: (keys: string[]) => void;
|
||||
segmentOptions: { value: string; field: string }[];
|
||||
getScrollElementScrollableHeight?: () => {
|
||||
scrollHeight: number;
|
||||
scrollTop: number;
|
||||
};
|
||||
defaultWait?: number;
|
||||
segmentedTop: {
|
||||
top: number; // The top offset for the sticky header
|
||||
offsetTop: number; // The offset top for the target
|
||||
};
|
||||
}) {
|
||||
const [holderHeight, setHolderHeight] = useState<number>(0);
|
||||
const boxHeightRef = useRef<number>(0);
|
||||
|
||||
const scrollToElement = useCallback(
|
||||
(
|
||||
el: HTMLElement,
|
||||
{ behavior = 'smooth', offsetTop = 0 }: ScrollOptions = {}
|
||||
) => {
|
||||
// find the nearest scrollable parent
|
||||
const scrollParent = (() => {
|
||||
let node: HTMLElement | null = el;
|
||||
while (node) {
|
||||
const { overflowY } = getComputedStyle(node);
|
||||
if (overflowY === 'auto' || overflowY === 'scroll') return node;
|
||||
node = node.parentElement;
|
||||
}
|
||||
return document.scrollingElement || document.documentElement;
|
||||
})();
|
||||
|
||||
const parentRect = scrollParent.getBoundingClientRect();
|
||||
const elRect = el.getBoundingClientRect();
|
||||
const top =
|
||||
elRect.top - parentRect.top + scrollParent.scrollTop - offsetTop;
|
||||
|
||||
scrollParent.scrollTo({ top, behavior });
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
/**
|
||||
* due to the scrollheight changes after expanding the segment and including the holder height.
|
||||
*
|
||||
*/
|
||||
const scrollToSegment = useMemoizedFn(
|
||||
async (val: string, options?: ScrollOptions) => {
|
||||
if (!activeKey.includes(val)) {
|
||||
setActiveKey([...activeKey, val]);
|
||||
await new Promise((r) => {
|
||||
setTimeout(r, options?.wait ?? defaultWait);
|
||||
});
|
||||
}
|
||||
|
||||
const current = segmentOptions.find((item) => item.value === val);
|
||||
if (!current?.field) return;
|
||||
|
||||
await new Promise(requestAnimationFrame);
|
||||
|
||||
const el: HTMLElement | null = document.querySelector(
|
||||
`[data-field="${current.field}"]`
|
||||
) as HTMLElement | null;
|
||||
|
||||
const targetRectTop = el?.getBoundingClientRect().top || 0;
|
||||
|
||||
const scroller = getScrollElementScrollableHeight?.() || {
|
||||
scrollHeight: 0,
|
||||
scrollTop: 0
|
||||
};
|
||||
|
||||
// remaining scroll height
|
||||
const remainingScrollHeight = scroller.scrollHeight - scroller.scrollTop;
|
||||
|
||||
// total distance from the top of the scroller to the target element
|
||||
const offsetDistance =
|
||||
targetRectTop - segmentedTop.offsetTop - segmentedTop.top;
|
||||
|
||||
let boxHeight = 0;
|
||||
|
||||
// verify boxHeight is correct, if setting the boxHeight causes the element to be hidden, use the previous boxHeight
|
||||
if (offsetDistance <= 0) {
|
||||
boxHeight = boxHeightRef.current;
|
||||
} else {
|
||||
boxHeight =
|
||||
offsetDistance - remainingScrollHeight + boxHeightRef.current;
|
||||
}
|
||||
|
||||
// update boxHeightRef
|
||||
boxHeightRef.current = boxHeight;
|
||||
|
||||
setHolderHeight(boxHeight);
|
||||
await new Promise(requestAnimationFrame);
|
||||
|
||||
if (el) scrollToElement(el, options);
|
||||
}
|
||||
);
|
||||
|
||||
return { scrollToSegment, holderHeight };
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
interface FinishFailedOptions {
|
||||
requiredFields: {
|
||||
[tab: string]: {
|
||||
sort: number;
|
||||
fields: string[];
|
||||
};
|
||||
};
|
||||
onTargetChange: (key: string) => void;
|
||||
updateActiveKey: (key: string[]) => void;
|
||||
}
|
||||
|
||||
const useFinishFailed = (options: FinishFailedOptions) => {
|
||||
const { requiredFields, onTargetChange, updateActiveKey } = options;
|
||||
const handleOnFinishFailed = (errorInfo: any) => {
|
||||
const { errorFields } = errorInfo;
|
||||
|
||||
console.log('Finish failed:', errorInfo);
|
||||
|
||||
if (errorFields && errorFields.length > 0) {
|
||||
const collapseKeys: { sort: number; key: string }[] = [];
|
||||
const names = errorFields.map((item: any) => item.name[0]);
|
||||
Object.entries(requiredFields).forEach(([tab, { fields, sort }]) => {
|
||||
const hasError = fields.some((field: string) => names.includes(field));
|
||||
if (hasError) {
|
||||
collapseKeys.push({ sort, key: tab });
|
||||
}
|
||||
});
|
||||
if (collapseKeys.length > 0) {
|
||||
const keys = collapseKeys
|
||||
.sort((a, b) => a.sort - b.sort)
|
||||
.map((item) => item.key);
|
||||
|
||||
updateActiveKey(keys);
|
||||
onTargetChange(collapseKeys[0].key);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
handleOnFinishFailed
|
||||
};
|
||||
};
|
||||
|
||||
export default useFinishFailed;
|
||||
@@ -1,40 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
const useScrollActiveChange = (options: {
|
||||
initalActiveKeys: string[];
|
||||
initialCollapseKeys?: string[];
|
||||
}) => {
|
||||
const [activeKey, setActiveKey] = useState<string[]>(
|
||||
options.initalActiveKeys
|
||||
);
|
||||
const [collapseKeys, setCollapseKeys] = useState<string[]>(
|
||||
options.initialCollapseKeys || options.initalActiveKeys
|
||||
);
|
||||
|
||||
const handleActiveChange = (key: string[]) => {
|
||||
setActiveKey(key);
|
||||
setCollapseKeys(key);
|
||||
};
|
||||
|
||||
const handleOnCollapseChange = (keys: string | string[]) => {
|
||||
const keysArray = Array.isArray(keys) ? keys : [keys];
|
||||
setActiveKey(keysArray);
|
||||
setCollapseKeys(keysArray);
|
||||
};
|
||||
|
||||
const updateActiveKey = (keys: string[]) => {
|
||||
setActiveKey((prev: string[]) => [...new Set([...prev, ...keys])]);
|
||||
setCollapseKeys((prev) => [...new Set([...prev, ...keys])]);
|
||||
};
|
||||
|
||||
return {
|
||||
activeKey,
|
||||
collapseKeys,
|
||||
setCollapseKeys,
|
||||
handleActiveChange,
|
||||
handleOnCollapseChange,
|
||||
updateActiveKey
|
||||
};
|
||||
};
|
||||
|
||||
export default useScrollActiveChange;
|
||||
@@ -1,36 +0,0 @@
|
||||
import { CloseCircleFilled } from '@ant-design/icons';
|
||||
import { Button } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
background-color: transparent !important;
|
||||
padding: 0;
|
||||
.anticon {
|
||||
color: var(--ant-color-text-quaternary);
|
||||
font-size: 12px !important;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
&:hover {
|
||||
.anticon {
|
||||
color: var(--ant-color-text-tertiary);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface SmallCloseButtonProps {
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const SmallCloseButton: React.FC<SmallCloseButtonProps> = ({ onClick }) => {
|
||||
return (
|
||||
<StyledButton
|
||||
icon={<CloseCircleFilled />}
|
||||
shape="circle"
|
||||
type="text"
|
||||
onClick={onClick}
|
||||
size="small"
|
||||
></StyledButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default SmallCloseButton;
|
||||
@@ -1,41 +0,0 @@
|
||||
.wrapper {
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
width: 0;
|
||||
transition: all var(--ant-motion-duration-slow) var(--ant-motion-ease-in-out);
|
||||
border-color: var(--ant-color-split);
|
||||
|
||||
&.show {
|
||||
width: 232px;
|
||||
border-right: 1px solid var(--ant-color-split);
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0 16px;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
margin-top: 8px;
|
||||
padding-inline: 8px;
|
||||
font-weight: 500;
|
||||
color: var(--ant-color-text-tertiary);
|
||||
}
|
||||
|
||||
.btn-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 24px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
import { MoreOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Transfer, TransferProps } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
type TransferKey = string | number | bigint;
|
||||
|
||||
const TransferWrap = styled.div`
|
||||
.ant-transfer-section {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
.anticon-more {
|
||||
display: none;
|
||||
}
|
||||
.ant-input-outlined {
|
||||
height: 32px;
|
||||
padding-block: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
.ant-transfer-actions {
|
||||
margin: 0 16px;
|
||||
gap: 12px;
|
||||
.ant-btn-icon-only {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.ant-transfer-list-content {
|
||||
&::-webkit-scrollbar {
|
||||
width: var(--scrollbar-size);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--color-scrollbar-thumb);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
.ant-transfer-list-content-item {
|
||||
&:hover {
|
||||
background-color: var(--ant-control-item-bg-hover);
|
||||
}
|
||||
&.ant-transfer-list-content-item-checked {
|
||||
background-color: unset;
|
||||
&:hover {
|
||||
background-color: var(--ant-control-item-bg-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-pagination {
|
||||
justify-content: center;
|
||||
}
|
||||
`;
|
||||
|
||||
interface TransferInnerProps extends TransferProps {
|
||||
total?: number;
|
||||
perPage?: number;
|
||||
onPageChange?: (page: number, perPage?: number) => void;
|
||||
dataSource?: Array<{ key: TransferKey; title: string }>;
|
||||
targetKeys?: TransferKey[];
|
||||
}
|
||||
|
||||
const TransferInner: React.FC<TransferInnerProps> = (props) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const renderAllLabels = (info: {
|
||||
selectedCount: number;
|
||||
totalCount: number;
|
||||
}) => {
|
||||
if (info.selectedCount) {
|
||||
return (
|
||||
<span style={{ color: 'var(--ant-color-text-secondary)' }}>
|
||||
{intl.formatMessage(
|
||||
{ id: 'common.select.count' },
|
||||
{ count: info.selectedCount }
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
return (
|
||||
<TransferWrap>
|
||||
<Transfer
|
||||
{...props}
|
||||
selectAllLabels={
|
||||
props.selectAllLabels || [renderAllLabels, renderAllLabels]
|
||||
}
|
||||
selectionsIcon={
|
||||
<MoreOutlined style={{ fontSize: 14, marginBottom: 3 }} />
|
||||
}
|
||||
></Transfer>
|
||||
</TransferWrap>
|
||||
);
|
||||
};
|
||||
|
||||
export default TransferInner;
|
||||
@@ -3,6 +3,7 @@ import { PageActionType } from '@/config/types';
|
||||
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||
import {
|
||||
AlertBlockInfo,
|
||||
ColumnWrapper,
|
||||
GSDrawer,
|
||||
IconFont,
|
||||
ModalFooter,
|
||||
@@ -13,7 +14,6 @@ import { Tabs } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect, useId, useMemo, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import ColumnWrapper from '../../_components/column-wrapper';
|
||||
import {
|
||||
BackendSourceValueMap,
|
||||
builtInBackendFields,
|
||||
|
||||
@@ -237,6 +237,10 @@ const BackendList = () => {
|
||||
});
|
||||
});
|
||||
|
||||
const handleRefresh = () => {
|
||||
fetchData({ query: { ...queryParams, page: 1 } });
|
||||
};
|
||||
|
||||
return (
|
||||
<PageBox>
|
||||
<FilterBar
|
||||
@@ -251,7 +255,7 @@ const BackendList = () => {
|
||||
selectHolder={intl.formatMessage({ id: 'backend.filter.source' })}
|
||||
buttonText={intl.formatMessage({ id: 'backend.button.add' })}
|
||||
handleClickPrimary={handleAddBackend}
|
||||
handleSearch={() => loadMore(1)}
|
||||
handleSearch={handleRefresh}
|
||||
handleSelectChange={handleFilterBySource}
|
||||
handleInputChange={handleNameChange}
|
||||
rowSelection={rowSelection}
|
||||
|
||||
@@ -124,6 +124,23 @@ const Instance: React.FC = () => {
|
||||
</Flex>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: intl.formatMessage({ id: 'models.form.env' }),
|
||||
children: (
|
||||
<Flex gap={8} wrap="wrap">
|
||||
{instanceData?.env
|
||||
? Object.entries(instanceData?.env || {}).map(
|
||||
([key, value], index: number) => (
|
||||
<Tag key={index} style={{ margin: 0 }}>
|
||||
{`${key}=${value}`}
|
||||
</Tag>
|
||||
)
|
||||
)
|
||||
: '-'}
|
||||
</Flex>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: intl.formatMessage({
|
||||
@@ -159,23 +176,6 @@ const Instance: React.FC = () => {
|
||||
)}
|
||||
</Flex>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: intl.formatMessage({ id: 'models.form.env' }),
|
||||
children: (
|
||||
<Flex gap={8} wrap="wrap">
|
||||
{instanceData?.env
|
||||
? Object.entries(instanceData?.env || {}).map(
|
||||
([key, value], index: number) => (
|
||||
<Tag key={index} style={{ margin: 0 }}>
|
||||
{`${key}=${value}`}
|
||||
</Tag>
|
||||
)
|
||||
)
|
||||
: '-'}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
];
|
||||
}, [detailData]);
|
||||
|
||||
@@ -57,7 +57,7 @@ const UsageByModel: React.FC<UsageByModelProps> = ({
|
||||
.fetchData({
|
||||
...commonParams,
|
||||
metric: 'total_tokens',
|
||||
group_by: ['route'],
|
||||
group_by: ['date', 'route'],
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
sort_by: '-total_tokens'
|
||||
@@ -67,7 +67,7 @@ const UsageByModel: React.FC<UsageByModelProps> = ({
|
||||
.fetchData({
|
||||
...commonParams,
|
||||
metric: 'api_requests',
|
||||
group_by: ['route'],
|
||||
group_by: ['date', 'route'],
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
sort_by: '-api_requests'
|
||||
|
||||
@@ -225,77 +225,29 @@ export const toUsagePieData = (
|
||||
return aggregateUsageByGroup(data, groupBy, metric);
|
||||
};
|
||||
|
||||
export type UsageTokenMetric = 'input_tokens' | 'output_tokens';
|
||||
|
||||
export interface UsageTokenSeriesDef {
|
||||
name: string;
|
||||
key: UsageTokenMetric;
|
||||
color: string;
|
||||
}
|
||||
|
||||
// Aggregates each group's input/output tokens into a stacked HBarChart shape,
|
||||
// so a single bar shows prompt (input) and completion (output) tokens side by
|
||||
// side. Rows sharing a group (e.g. the same user across dates) are summed, then
|
||||
// ranked by combined tokens and capped at the top 10.
|
||||
export const toUsageTokenBreakdownData = (
|
||||
export const toUsageRankData = (
|
||||
data: UsageBreakdownResponse | null | undefined,
|
||||
groupBy: UsageGroupBy,
|
||||
seriesDefs: UsageTokenSeriesDef[]
|
||||
seriesName: string,
|
||||
color: string
|
||||
) => {
|
||||
const itemMap = new Map<string, { total: number; values: number[] }>();
|
||||
const items = getUsageResponseItems(data);
|
||||
|
||||
items.forEach((item: BreakdownItem) => {
|
||||
const name = buildUsageLabel(item, groupBy);
|
||||
const entry = itemMap.get(name) || {
|
||||
total: 0,
|
||||
values: seriesDefs.map(() => 0)
|
||||
};
|
||||
|
||||
seriesDefs.forEach((def, index) => {
|
||||
const value = Number((item as any)?.[def.key] ?? 0);
|
||||
entry.values[index] += value;
|
||||
entry.total += value;
|
||||
});
|
||||
|
||||
itemMap.set(name, entry);
|
||||
});
|
||||
|
||||
const ranked = Array.from(itemMap.entries())
|
||||
.filter(([, entry]) => entry.total > 0)
|
||||
.sort((a, b) => b[1].total - a[1].total)
|
||||
.slice(0, 10);
|
||||
|
||||
const names = ranked.map(([name]) => name);
|
||||
|
||||
// Round only the outer ends of the stacked bar; the seam where the input and
|
||||
// output segments meet stays square ([topLeft, topRight, bottomRight, bottomLeft]).
|
||||
const radius = 2;
|
||||
const getBorderRadius = (index: number, count: number) => {
|
||||
if (count <= 1) {
|
||||
return [radius, radius, radius, radius];
|
||||
}
|
||||
if (index === 0) {
|
||||
return [radius, 0, 0, radius];
|
||||
}
|
||||
if (index === count - 1) {
|
||||
return [0, radius, radius, 0];
|
||||
}
|
||||
return [0, 0, 0, 0];
|
||||
};
|
||||
const items = aggregateUsageByGroup(data, groupBy, 'total_tokens');
|
||||
const names = items.map((item) => item.name);
|
||||
|
||||
return {
|
||||
names,
|
||||
series: seriesDefs.map((def, index) => ({
|
||||
name: def.name,
|
||||
color: def.color,
|
||||
data: ranked.map(([name, entry]) => ({
|
||||
name,
|
||||
value: entry.values[index],
|
||||
itemStyle: {
|
||||
borderRadius: getBorderRadius(index, seriesDefs.length)
|
||||
}
|
||||
}))
|
||||
}))
|
||||
series: [
|
||||
{
|
||||
name: seriesName,
|
||||
color,
|
||||
data: items.map((item) => ({
|
||||
name: item.name,
|
||||
value: item.value,
|
||||
itemStyle: {
|
||||
borderRadius: [2, 2, 2, 2]
|
||||
}
|
||||
}))
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
import useQueryTimeSeriesData from '@/pages/usage/services/use-query-timeseries-data';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import {
|
||||
baseColorMap,
|
||||
DashboardUsageCommonParams,
|
||||
toUsageTokenBreakdownData
|
||||
toUsageRankData
|
||||
} from '../config';
|
||||
|
||||
export default function useTopTokenUsageByUser(
|
||||
commonParams: DashboardUsageCommonParams
|
||||
) {
|
||||
const intl = useIntl();
|
||||
const query = useQueryTimeSeriesData({
|
||||
key: 'topTokenUsageByUserData'
|
||||
});
|
||||
const tokenUsageText = intl.formatMessage({ id: 'dashboard.tokens' });
|
||||
|
||||
useEffect(() => {
|
||||
query
|
||||
.fetchData({
|
||||
...commonParams,
|
||||
metric: 'total_tokens',
|
||||
group_by: ['user'],
|
||||
group_by: ['date', 'user'],
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
sort_by: '-total_tokens'
|
||||
@@ -28,19 +31,13 @@ export default function useTopTokenUsageByUser(
|
||||
|
||||
const rankData = useMemo(
|
||||
() =>
|
||||
toUsageTokenBreakdownData(query.detailData, 'user', [
|
||||
{
|
||||
name: 'Prompt Tokens',
|
||||
key: 'input_tokens',
|
||||
color: baseColorMap.base
|
||||
},
|
||||
{
|
||||
name: 'Completion Tokens',
|
||||
key: 'output_tokens',
|
||||
color: baseColorMap.baseR3
|
||||
}
|
||||
]),
|
||||
[query.detailData]
|
||||
toUsageRankData(
|
||||
query.detailData,
|
||||
'user',
|
||||
tokenUsageText,
|
||||
baseColorMap.base
|
||||
),
|
||||
[query.detailData, tokenUsageText]
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { PageAction } from '@/config';
|
||||
import FormOverlayView from '@/pages/_components/form-overlay-view';
|
||||
import { ModalFooter } from '@gpustack/core-ui';
|
||||
import { ModalFooter, SubDrawer } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { useRef, useState } from 'react';
|
||||
import { FormData as PublicKeyFormData } from '../../public-keys/config/types';
|
||||
@@ -45,7 +44,7 @@ const PublicKeyOverlay: React.FC<PublicKeyOverlayProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<FormOverlayView
|
||||
<SubDrawer
|
||||
title={intl.formatMessage({ id: 'gpuservice.publicKey.add' })}
|
||||
open={open}
|
||||
width={drawerWidth}
|
||||
@@ -70,7 +69,7 @@ const PublicKeyOverlay: React.FC<PublicKeyOverlayProps> = ({
|
||||
open={open}
|
||||
onFinish={handleFinish}
|
||||
/>
|
||||
</FormOverlayView>
|
||||
</SubDrawer>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { PageAction } from '@/config';
|
||||
import FormOverlayView from '@/pages/_components/form-overlay-view';
|
||||
import { FormContext } from '@/pages/gpu-service/storage/config/form-context';
|
||||
import useQueryStorageClass from '@/pages/gpu-service/storage/services/use-query-storage-class';
|
||||
import { ModalFooter } from '@gpustack/core-ui';
|
||||
import { ModalFooter, SubDrawer } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { FormData as StorageFormData } from '../../storage/config/types';
|
||||
@@ -52,7 +51,7 @@ const StorageOverlay: React.FC<StorageOverlayProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<FormOverlayView
|
||||
<SubDrawer
|
||||
title={intl.formatMessage({ id: 'gpuservice.storage.add' })}
|
||||
open={open}
|
||||
width={drawerWidth}
|
||||
@@ -79,7 +78,7 @@ const StorageOverlay: React.FC<StorageOverlayProps> = ({
|
||||
onFinish={handleFinish}
|
||||
/>
|
||||
</FormContext.Provider>
|
||||
</FormOverlayView>
|
||||
</SubDrawer>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { PageActionType } from '@/config/types';
|
||||
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||
import { ModalFooter } from '@gpustack/core-ui';
|
||||
import { FormDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { useRef } from 'react';
|
||||
import FormDrawer from '../../../_components/form-drawer';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
import GPUServicePublicKeyForm from '../forms';
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { PageActionType } from '@/config/types';
|
||||
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||
import { ModalFooter } from '@gpustack/core-ui';
|
||||
import { FormDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { useRef } from 'react';
|
||||
import FormDrawer from '../../../_components/form-drawer';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
import GPUServiceStorageTypeForm from '../forms';
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { PageActionType } from '@/config/types';
|
||||
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||
import { ModalFooter } from '@gpustack/core-ui';
|
||||
import { FormDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { useRef } from 'react';
|
||||
import FormDrawer from '../../../_components/form-drawer';
|
||||
import { FormContext } from '../config/form-context';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
import GPUServiceStorageForm from '../forms';
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { PageActionType } from '@/config/types';
|
||||
import useSubmitLock from '@/hooks/use-submit-lock';
|
||||
import { ModalFooter } from '@gpustack/core-ui';
|
||||
import { FormDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { useRef } from 'react';
|
||||
import FormDrawer from '../../../_components/form-drawer';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
import GPUServiceTemplateForm from '../forms';
|
||||
|
||||
|
||||
@@ -129,6 +129,10 @@ const GPUServiceTemplates: React.FC = () => {
|
||||
});
|
||||
});
|
||||
|
||||
const handleRefresh = () => {
|
||||
fetchData({ query: { ...queryParams, page: 1 } });
|
||||
};
|
||||
|
||||
return (
|
||||
<PageBox>
|
||||
<FilterBar
|
||||
@@ -145,7 +149,7 @@ const GPUServiceTemplates: React.FC = () => {
|
||||
})}
|
||||
buttonText={intl.formatMessage({ id: 'gpuservice.template.add' })}
|
||||
handleClickPrimary={handleAddTemplate}
|
||||
handleSearch={handleSearch}
|
||||
handleSearch={handleRefresh}
|
||||
handleSelectChange={handleFilterByManufacturer}
|
||||
handleInputChange={handleNameChange}
|
||||
rowSelection={rowSelection}
|
||||
|
||||
@@ -27,7 +27,6 @@ const Catalog: React.FC = () => {
|
||||
const {
|
||||
dataSource,
|
||||
queryParams,
|
||||
handleSearch,
|
||||
fetchData,
|
||||
handleQueryChange,
|
||||
loadMore,
|
||||
@@ -112,6 +111,10 @@ const Catalog: React.FC = () => {
|
||||
navigate('/models/deployments');
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
fetchData({ query: { ...queryParams, page: 1 } });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (dataSource.loadend) {
|
||||
const getCatalogSource = async () => {
|
||||
@@ -138,7 +141,7 @@ const Catalog: React.FC = () => {
|
||||
marginBottom={22}
|
||||
marginTop={0}
|
||||
buttonText={intl.formatMessage({ id: 'models.catalog.button.explore' })}
|
||||
handleSearch={() => loadMore(1)}
|
||||
handleSearch={handleSearch}
|
||||
handleSelectChange={handleCategoryChange}
|
||||
handleClickPrimary={handleDeployFromOtherHubs}
|
||||
handleInputChange={handleNameChange}
|
||||
|
||||
@@ -2,14 +2,13 @@ import { getRequestId } from '@/atoms/models';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import useDeferredRequest from '@/hooks/use-deferred-request';
|
||||
import { ClusterStatusValueMap } from '@/pages/cluster-management/config';
|
||||
import { GSDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { ColumnWrapper, GSDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { Button } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FC, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import ColumnWrapper from '../../../_components/column-wrapper';
|
||||
import {
|
||||
defaultFormValues,
|
||||
DeployFormKeyMap,
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { ProviderValueMap } from '@/pages/cluster-management/config';
|
||||
import { GSDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { ColumnWrapper, GSDrawer, ModalFooter } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { debounce } from 'lodash';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import ColumnWrapper from '../../../_components/column-wrapper';
|
||||
import { modelSourceMap } from '../../config';
|
||||
import { FormData } from '../../config/types';
|
||||
import HFModelFile from '../model-source/hf-model-file';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { AutoTooltip } from '@gpustack/core-ui';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import '../style/gpu-card.less';
|
||||
@@ -24,6 +23,7 @@ const ItemInfo = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
white-space: break-spaces;
|
||||
font-size: 13px;
|
||||
`;
|
||||
|
||||
const Description = styled.div`
|
||||
@@ -76,7 +76,7 @@ const GPUCard: React.FC<{
|
||||
/ {convertFileSize(data?.memory?.total || 0)}
|
||||
</span>
|
||||
</ItemInfo>
|
||||
<ItemInfo>
|
||||
{/* <ItemInfo>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'resources.table.gpuutilization' })}
|
||||
:{' '}
|
||||
@@ -85,7 +85,7 @@ const GPUCard: React.FC<{
|
||||
? _.round(data?.memory?.utilization_rate || 0, 2)
|
||||
: _.round(data.memory?.allocated / data.memory?.total, 2) * 100}
|
||||
%
|
||||
</ItemInfo>
|
||||
</ItemInfo> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ const ScheduleTypeForm: React.FC = () => {
|
||||
<SealCascader
|
||||
required
|
||||
showSearch
|
||||
expandTrigger="hover"
|
||||
expandTrigger="click"
|
||||
multiple={
|
||||
form.getFieldValue('backend') !== backendOptionsMap.voxBox
|
||||
}
|
||||
@@ -184,6 +184,13 @@ const ScheduleTypeForm: React.FC = () => {
|
||||
root: 'cascader-popup-wrapper gpu-selector'
|
||||
}
|
||||
}}
|
||||
styles={{
|
||||
popup: {
|
||||
listItem: {
|
||||
maxWidth: 'unset'
|
||||
}
|
||||
}
|
||||
}}
|
||||
maxTagCount={1}
|
||||
label={intl.formatMessage({ id: 'models.form.gpuselector' })}
|
||||
options={gpuOptions}
|
||||
|
||||
@@ -145,6 +145,12 @@ const UserModels: React.FC = () => {
|
||||
return result;
|
||||
}, [dataSource.dataList]);
|
||||
|
||||
const handleRefresh = () => {
|
||||
fetchData({
|
||||
query: { ...queryParams, page: 1 }
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<PageBox>
|
||||
<PageTools
|
||||
@@ -192,7 +198,7 @@ const UserModels: React.FC = () => {
|
||||
type="text"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
icon={<SyncOutlined></SyncOutlined>}
|
||||
onClick={handleSearch}
|
||||
onClick={handleRefresh}
|
||||
></Button>
|
||||
</Space>
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ const Organizations: React.FC = () => {
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<div style={{ textAlign: 'center', marginTop: 56 }}>
|
||||
<Button
|
||||
type="primary"
|
||||
href="https://gpustack.ai/enterprise"
|
||||
|
||||
@@ -25,7 +25,8 @@ import TokenTab from './token-tab';
|
||||
const Usage: React.FC = () => {
|
||||
const access = useAccess();
|
||||
const intl = useIntl();
|
||||
// Land on the cross-resource Summary by default.
|
||||
|
||||
const canSeeGpuService = !!access?.canSeeGpuService;
|
||||
const [activeKey, setActiveKey] = useState<string>('summary');
|
||||
|
||||
const items: TabsProps['items'] = useMemo(() => {
|
||||
@@ -67,7 +68,13 @@ const Usage: React.FC = () => {
|
||||
if (!item.access) return true;
|
||||
return (access as Record<string, boolean>)[item.access];
|
||||
});
|
||||
}, [intl, access]);
|
||||
}, [intl, access.canSeeGpuService]);
|
||||
|
||||
// Only the Tokens tab is available — render it on its own without the
|
||||
// single-item tab bar.
|
||||
if (!canSeeGpuService) {
|
||||
return <TokenTab />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
|
||||
@@ -58,7 +58,9 @@ const useInstancesColumns = (groupKey: GroupKey) => {
|
||||
intl,
|
||||
categories: ['cpu', 'ram'],
|
||||
title:
|
||||
(row.gpu_count ?? 0) > 0 ? instanceTypeLabel(row) : 'CPU Only'
|
||||
!!row.gpu_count || !!row.vram_mib
|
||||
? instanceTypeLabel(row)
|
||||
: 'CPU Only'
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Access probes used to gate Kubernetes-only menus (GPU Service / the
|
||||
* full Usage page).
|
||||
*
|
||||
* These live outside `src/app.tsx` because umi treats every export from
|
||||
* the runtime-config file as a registration key — exporting helpers from
|
||||
* there throws "register failed, invalid key". `getInitialState` (in
|
||||
* app.tsx) and the login flow both import from here.
|
||||
*/
|
||||
import { queryClusterList } from '@/pages/cluster-management/apis';
|
||||
import { ProviderValueMap } from '@/pages/cluster-management/config';
|
||||
import { queryResourceEvents } from '@/pages/usage/apis/resource';
|
||||
|
||||
// Probes the caller's cluster list once so access predicates can gate
|
||||
// GPU Service (Kubernetes-only). Cheap (one list request) and never
|
||||
// blocks login — any failure just falls back to `undefined`, which
|
||||
// the predicate treats as "unknown / don't restrict beyond role".
|
||||
// The result is also mirrored into sessionStorage so access extensions
|
||||
// that run without the initialState argument can read it (e.g. to
|
||||
// override the admin shortcut in scopes where the menu shouldn't
|
||||
// show even for admins).
|
||||
const HAS_K8S_CLUSTER_KEY = 'hasKubernetesCluster';
|
||||
export const probeHasKubernetesCluster = async (): Promise<
|
||||
boolean | undefined
|
||||
> => {
|
||||
try {
|
||||
const res = await queryClusterList(
|
||||
{ page: -1 },
|
||||
{
|
||||
skipErrorHandler: true
|
||||
}
|
||||
);
|
||||
const value = (res?.items ?? []).some(
|
||||
(c) => c?.provider === ProviderValueMap.Kubernetes
|
||||
);
|
||||
try {
|
||||
window.sessionStorage.setItem(HAS_K8S_CLUSTER_KEY, JSON.stringify(value));
|
||||
} catch {
|
||||
// sessionStorage may be unavailable (Safari private mode); the
|
||||
// access predicate already handles a missing value as "unknown".
|
||||
}
|
||||
return value;
|
||||
} catch (error) {
|
||||
console.error('probeHasKubernetesCluster error', error);
|
||||
try {
|
||||
window.sessionStorage.removeItem(HAS_K8S_CLUSTER_KEY);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// Probes whether the caller has ANY resource-usage events (GPU/CPU instance or
|
||||
// storage lifecycle). Used alongside the cluster probe so a user who has run
|
||||
// GPU instances still sees GPU Service / the full Usage page even if they
|
||||
// currently have no Kubernetes cluster. Mirrored into sessionStorage for the
|
||||
// access extensions; any failure → undefined ("unknown — don't restrict").
|
||||
const HAS_RESOURCE_EVENTS_KEY = 'hasResourceEvents';
|
||||
export const probeHasResourceEvents = async (): Promise<
|
||||
boolean | undefined
|
||||
> => {
|
||||
try {
|
||||
// No date range = "ever"; scope is clamped to the caller server-side.
|
||||
const res = await queryResourceEvents(
|
||||
{ perPage: 1 },
|
||||
{
|
||||
skipErrorHandler: true
|
||||
}
|
||||
);
|
||||
const value = (res?.pagination?.total ?? 0) > 0;
|
||||
try {
|
||||
window.sessionStorage.setItem(
|
||||
HAS_RESOURCE_EVENTS_KEY,
|
||||
JSON.stringify(value)
|
||||
);
|
||||
} catch {
|
||||
// sessionStorage may be unavailable; predicate treats missing as unknown.
|
||||
}
|
||||
return value;
|
||||
} catch (error) {
|
||||
console.error('probeHasResourceEvents error', error);
|
||||
try {
|
||||
window.sessionStorage.removeItem(HAS_RESOURCE_EVENTS_KEY);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// Runs both access probes in parallel. Used after login (when
|
||||
// `getInitialState` skipped them because the app booted on the login
|
||||
// page) so the access predicate has definitive cluster / resource-event
|
||||
// answers before the user navigates — otherwise GPU Service / the full
|
||||
// Usage page flash on (undefined => "don't restrict") and only collapse
|
||||
// to the correct set on the next refresh.
|
||||
export const probeAccessFlags = async (): Promise<{
|
||||
hasKubernetesCluster?: boolean;
|
||||
hasResourceEvents?: boolean;
|
||||
}> => {
|
||||
const [hasKubernetesCluster, hasResourceEvents] = await Promise.all([
|
||||
probeHasKubernetesCluster(),
|
||||
probeHasResourceEvents()
|
||||
]);
|
||||
return { hasKubernetesCluster, hasResourceEvents };
|
||||
};
|
||||
|
||||
// Module-scoped marker for "did `getInitialState` actually run the access
|
||||
// probes during THIS page load". It resets to `false` on every full
|
||||
// reload (the module is re-evaluated) and stays sticky across SPA
|
||||
// navigations within the same load.
|
||||
//
|
||||
// The layout uses it to decide whether it must probe: on a refresh of an
|
||||
// authenticated page `getInitialState` already probed (marks `true`), so
|
||||
// the layout skips and avoids a duplicate request; on a first login the
|
||||
// app booted on `/login` where `getInitialState` skipped probing (stays
|
||||
// `false`), so the layout is the one that resolves the flags. Keeping
|
||||
// this in module scope — rather than reading the flag values off
|
||||
// `initialState` — decouples the decision from React's state-update
|
||||
// timing, which is what made the earlier flag-gated effect fragile.
|
||||
let initialStateDidProbe = false;
|
||||
export const markInitialStateProbed = () => {
|
||||
initialStateDidProbe = true;
|
||||
};
|
||||
export const didInitialStateProbe = () => initialStateDidProbe;
|
||||
Reference in New Issue
Block a user