This is an automated email from the ASF dual-hosted git repository.

shuai pushed a commit to branch feat/1.4.0/personal
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git


The following commit(s) were added to refs/heads/feat/1.4.0/personal by this 
push:
     new 514f3702 fix: badge list and badge detail docking api
514f3702 is described below

commit 514f37029b23a099ba3e316040896032da80683c
Author: shuai <[email protected]>
AuthorDate: Thu Aug 8 18:28:37 2024 +0800

    fix: badge list and badge detail docking api
---
 ui/package.json                                    |   3 +-
 ui/pnpm-lock.yaml                                  | 988 +--------------------
 ui/src/common/interface.ts                         |  32 +
 ui/src/components/CardBadge/index.tsx              |  46 +-
 ui/src/index.scss                                  |  10 +
 .../pages/Badges/Detail/components/Badge/index.tsx |  93 ++
 .../{ => Detail/components/HeaderLoader}/index.tsx |  40 +-
 .../Badges/Detail/components/Loader/index.tsx      |  55 ++
 ui/src/pages/Badges/Detail/index.tsx               | 131 +--
 ui/src/pages/Badges/index.tsx                      |  21 +-
 .../Users/Personal/components/Badges/index.tsx     |   7 +-
 .../Users/Personal/components/Overview/index.tsx   |   7 +-
 ui/src/services/client/badges.ts                   |  64 ++
 ui/src/services/client/index.ts                    |   1 +
 14 files changed, 419 insertions(+), 1079 deletions(-)

diff --git a/ui/package.json b/ui/package.json
index 352e28de..ab428bb4 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -45,8 +45,7 @@
     "react-router-dom": "^6.22.3",
     "semver": "^7.3.8",
     "swr": "^1.3.0",
-    "zustand": "^4.1.1",
-    "demo": "workspace:*"
+    "zustand": "^4.1.1"
   },
   "devDependencies": {
     "@commitlint/cli": "^17.0.3",
diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml
index 98148017..db5e7937 100644
--- a/ui/pnpm-lock.yaml
+++ b/ui/pnpm-lock.yaml
@@ -44,9 +44,6 @@ importers:
       dayjs:
         specifier: ^1.11.5
         version: 1.11.5
-      demo:
-        specifier: workspace:*
-        version: link:src/plugins/demo
       diff:
         specifier: ^5.1.0
         version: 5.1.0
@@ -232,52 +229,6 @@ importers:
         specifier: ^0.8.0
         version: 0.8.0
 
-  src/plugins/demo:
-    dependencies:
-      react:
-        specifier: ^18.2.0
-        version: 18.2.0
-      react-bootstrap:
-        specifier: ^2.10.0
-        version: 2.10.0(@types/[email protected])([email protected])([email protected])
-      react-dom:
-        specifier: ^18.2.0
-        version: 18.2.0([email protected])
-      react-i18next:
-        specifier: ^11.18.3
-        version: 11.18.6([email protected])([email protected])([email protected])
-    devDependencies:
-      '@modyfi/vite-plugin-yaml':
-        specifier: ^1.1.0
-        version: 1.1.0([email protected])([email protected])
-      '@typescript-eslint/eslint-plugin':
-        specifier: ^6.0.0
-        version: 
6.11.0(@typescript-eslint/[email protected])([email protected])([email protected])
-      '@typescript-eslint/parser':
-        specifier: ^6.0.0
-        version: 6.11.0([email protected])([email protected])
-      '@vitejs/plugin-react-swc':
-        specifier: ^3.3.2
-        version: 3.7.0([email protected])
-      eslint:
-        specifier: ^8.45.0
-        version: 8.53.0
-      eslint-plugin-react-hooks:
-        specifier: ^4.6.0
-        version: 4.6.0([email protected])
-      eslint-plugin-react-refresh:
-        specifier: ^0.4.3
-        version: 0.4.9([email protected])
-      typescript:
-        specifier: ^5.0.2
-        version: 5.5.4
-      vite:
-        specifier: ^4.4.5
-        version: 4.5.3(@types/[email protected])([email protected])
-      vite-plugin-dts:
-        specifier: ^3.9.1
-        version: 
3.9.1(@types/[email protected])([email protected])([email protected])([email protected])
-
 packages:
 
   /@aashutoshrathi/[email protected]:
@@ -598,14 +549,6 @@ packages:
     dependencies:
       '@babel/types': 7.19.0
 
-  /@babel/[email protected]:
-    resolution: {integrity: 
sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA==}
-    engines: {node: '>=6.0.0'}
-    hasBin: true
-    dependencies:
-      '@babel/types': 7.23.6
-    dev: true
-
   
/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/[email protected]):
     resolution: {integrity: 
sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==}
     engines: {node: '>=6.9.0'}
@@ -2248,204 +2191,6 @@ packages:
       postcss: 8.4.16
       postcss-selector-parser: 6.0.10
 
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
-    engines: {node: '>=12'}
-    cpu: [loong64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
-    engines: {node: '>=12'}
-    cpu: [mips64el]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
-    engines: {node: '>=12'}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
-    engines: {node: '>=12'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [netbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [openbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [sunos]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
   /@eslint-community/[email protected]([email protected]):
     resolution: {integrity: 
sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -2960,63 +2705,6 @@ packages:
       '@lezer/lr': 1.4.0
     dev: false
 
-  /@microsoft/[email protected](@types/[email protected]):
-    resolution: {integrity: 
sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==}
-    dependencies:
-      '@microsoft/tsdoc': 0.14.2
-      '@microsoft/tsdoc-config': 0.16.2
-      '@rushstack/node-core-library': 4.0.2(@types/[email protected])
-    transitivePeerDependencies:
-      - '@types/node'
-    dev: true
-
-  /@microsoft/[email protected](@types/[email protected]):
-    resolution: {integrity: 
sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==}
-    hasBin: true
-    dependencies:
-      '@microsoft/api-extractor-model': 7.28.13(@types/[email protected])
-      '@microsoft/tsdoc': 0.14.2
-      '@microsoft/tsdoc-config': 0.16.2
-      '@rushstack/node-core-library': 4.0.2(@types/[email protected])
-      '@rushstack/rig-package': 0.5.2
-      '@rushstack/terminal': 0.10.0(@types/[email protected])
-      '@rushstack/ts-command-line': 4.19.1(@types/[email protected])
-      lodash: 4.17.21
-      minimatch: 3.0.4
-      resolve: 1.22.1
-      semver: 7.5.4
-      source-map: 0.6.1
-      typescript: 5.4.2
-    transitivePeerDependencies:
-      - '@types/node'
-    dev: true
-
-  /@microsoft/[email protected]:
-    resolution: {integrity: 
sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==}
-    dependencies:
-      '@microsoft/tsdoc': 0.14.2
-      ajv: 6.12.6
-      jju: 1.4.0
-      resolve: 1.19.0
-    dev: true
-
-  /@microsoft/[email protected]:
-    resolution: {integrity: 
sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==}
-    dev: true
-
-  /@modyfi/[email protected]([email protected])([email protected]):
-    resolution: {integrity: 
sha512-L26xfzkSo1yamODCAtk/ipVlL6OEw2bcJ92zunyHu8zxi7+meV0zefA9xscRMDCsMY8xL3C3wi3DhMiPxcbxbw==}
-    peerDependencies:
-      vite: ^3.2.7 || ^4.0.5 || ^5.0.5
-    dependencies:
-      '@rollup/pluginutils': 5.1.0([email protected])
-      js-yaml: 4.1.0
-      tosource: 2.0.0-alpha.3
-      vite: 4.5.3(@types/[email protected])([email protected])
-    transitivePeerDependencies:
-      - rollup
-    dev: true
-
   /@nicolo-ribaudo/[email protected]:
     resolution: {integrity: 
sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
     dependencies:
@@ -3188,72 +2876,9 @@ packages:
       picomatch: 2.3.1
       rollup: 2.79.0
 
-  /@rollup/[email protected]([email protected]):
-    resolution: {integrity: 
sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
-    engines: {node: '>=14.0.0'}
-    peerDependencies:
-      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
-    peerDependenciesMeta:
-      rollup:
-        optional: true
-    dependencies:
-      '@types/estree': 1.0.5
-      estree-walker: 2.0.2
-      picomatch: 2.3.1
-      rollup: 2.79.0
-    dev: true
-
   /@rushstack/[email protected]:
     resolution: {integrity: 
sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==}
 
-  /@rushstack/[email protected](@types/[email protected]):
-    resolution: {integrity: 
sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==}
-    peerDependencies:
-      '@types/node': '*'
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-    dependencies:
-      '@types/node': 16.11.59
-      fs-extra: 7.0.1
-      import-lazy: 4.0.0
-      jju: 1.4.0
-      resolve: 1.22.1
-      semver: 7.5.4
-      z-schema: 5.0.5
-    dev: true
-
-  /@rushstack/[email protected]:
-    resolution: {integrity: 
sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==}
-    dependencies:
-      resolve: 1.22.1
-      strip-json-comments: 3.1.1
-    dev: true
-
-  /@rushstack/[email protected](@types/[email protected]):
-    resolution: {integrity: 
sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==}
-    peerDependencies:
-      '@types/node': '*'
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-    dependencies:
-      '@rushstack/node-core-library': 4.0.2(@types/[email protected])
-      '@types/node': 16.11.59
-      supports-color: 8.1.1
-    dev: true
-
-  /@rushstack/[email protected](@types/[email protected]):
-    resolution: {integrity: 
sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==}
-    dependencies:
-      '@rushstack/terminal': 0.10.0(@types/[email protected])
-      '@types/argparse': 1.0.38
-      argparse: 1.0.10
-      string-argv: 0.3.2
-    transitivePeerDependencies:
-      - '@types/node'
-    dev: true
-
   /@sinclair/[email protected]:
     resolution: {integrity: 
sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw==}
 
@@ -3370,141 +2995,12 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-CTkHa6MJdov9t41vuV2kmQIMu+Q19LrEHGIR/UiJYH06SC/sOu35ZZH8DyfLp9ZoaCn21gwgWd61ixOGQlwzTw==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-mun623y6rCoZ2EFIYfIRqXYRFufJOopoYSJcxYhZUrfTpAvQ1zLngjQpWCUU1krggXR2U0PQj+ls0DfXUTraNg==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-4Jz4UcIcvZNMp9qoHbBx35bo3rjt8hpYLPqnR4FFq6gkAsJIMFC56UhRZwdEQoDuYiOFMBnnrsg31Fyo6YQypA==}
-    engines: {node: '>=10'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-p+U/M/oqV7HC4erQ5TVWHhJU1984QD+wQBPxslAYq751bOQGm0R/mXK42GjugqjnR6yYrAiwKKbpq4iWVXNePA==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    libc: [glibc]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-s6VzyaJwaRGTi2mz2h6Ywxfmgpkc69IxhuMzl+sl34plH0V0RgnZDm14HoCGIKIzRk4+a2EcBV1ZLAfWmPACQg==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    libc: [musl]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-IrFY48C356Z2dU2pjYg080yvMXzmSV3Lmm/Wna4cfcB1nkVLjWsuYwwRAk9CY7E19c+q8N1sMNggubAUDYoX2g==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    libc: [glibc]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-qoLgxBlBnnyUEDu5vmRQqX90h9jldU1JXI96e6eh2d1gJyKRA0oSK7xXmTzorv1fGHiHulv9qiJOUG+g6uzJWg==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    libc: [musl]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-OAd7jVVJ7nb0Ev80VAa1aeK+FldPeC4eZ35H4Qn6EICzIz0iqJo2T33qLKkSZiZEBKSoF4KcwrqYfkjLOp5qWg==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-31+Le1NyfSnILFV9+AhxfFOG0DK0272MNhbIlbcv4w/iqpjkhaOnNQnLsYJD1Ow7lTX1MtIZzTjOhRlzSviRWg==}
-    engines: {node: '>=10'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-jVQPbYrwcuueI4QB0fHC29SVrkFOBcfIspYDlgSoHnEz6tmLMqUy+txZUypY/ZH/KaK0HEY74JkzgbRC1S6LFQ==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-HHAlbXjWI6Kl9JmmUW1LSygT1YbblXgj2UvvDzMkTBPRzYMhW6xchxdO8HbtMPtFYRt/EQq9u1z7j4ttRSrFsA==}
-    engines: {node: '>=10'}
-    requiresBuild: true
-    peerDependencies:
-      '@swc/helpers': '*'
-    peerDependenciesMeta:
-      '@swc/helpers':
-        optional: true
-    dependencies:
-      '@swc/counter': 0.1.3
-      '@swc/types': 0.1.12
-    optionalDependencies:
-      '@swc/core-darwin-arm64': 1.7.3
-      '@swc/core-darwin-x64': 1.7.3
-      '@swc/core-linux-arm-gnueabihf': 1.7.3
-      '@swc/core-linux-arm64-gnu': 1.7.3
-      '@swc/core-linux-arm64-musl': 1.7.3
-      '@swc/core-linux-x64-gnu': 1.7.3
-      '@swc/core-linux-x64-musl': 1.7.3
-      '@swc/core-win32-arm64-msvc': 1.7.3
-      '@swc/core-win32-ia32-msvc': 1.7.3
-      '@swc/core-win32-x64-msvc': 1.7.3
-    dev: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
-    dev: true
-
   /@swc/[email protected]:
     resolution: {integrity: 
sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==}
     dependencies:
       tslib: 2.6.2
     dev: false
 
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==}
-    dependencies:
-      '@swc/counter': 0.1.3
-    dev: true
-
   /@testing-library/[email protected]:
     resolution: {integrity: 
sha512-oEvsm2B/WtcHKE+IcEeeCqNU/ltFGaVyGbpcm4g/2ytuT49jrlH9x5qRKL/H3A6yfM4YAbSbC0ceT5+9CEXnLg==}
     engines: {node: '>=12'}
@@ -3578,10 +3074,6 @@ packages:
   /@tsconfig/[email protected]:
     resolution: {integrity: 
sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==}
 
-  /@types/[email protected]:
-    resolution: {integrity: 
sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
-    dev: true
-
   /@types/[email protected]:
     resolution: {integrity: 
sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==}
     dev: true
@@ -3897,43 +3389,14 @@ packages:
       debug: 4.3.4
       eslint: 8.53.0
       ignore: 5.2.4
-      regexpp: 3.2.0
-      semver: 7.5.4
-      tsutils: 3.21.0([email protected])
-      typescript: 4.9.5
-    transitivePeerDependencies:
-      - supports-color
-
-  
/@typescript-eslint/[email protected](@typescript-eslint/[email protected])([email protected])([email protected]):
-    resolution: {integrity: 
sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@eslint-community/regexpp': 4.10.0
-      '@typescript-eslint/parser': 6.11.0([email protected])([email protected])
-      '@typescript-eslint/scope-manager': 6.11.0
-      '@typescript-eslint/type-utils': 6.11.0([email protected])([email protected])
-      '@typescript-eslint/utils': 6.11.0([email protected])([email protected])
-      '@typescript-eslint/visitor-keys': 6.11.0
-      debug: 4.3.4
-      eslint: 8.53.0
-      graphemer: 1.4.0
-      ignore: 5.2.4
-      natural-compare: 1.4.0
+      regexpp: 3.2.0
       semver: 7.5.4
-      ts-api-utils: 1.0.3([email protected])
+      tsutils: 3.21.0([email protected])
       typescript: 4.9.5
     transitivePeerDependencies:
       - supports-color
-    dev: true
 
-  
/@typescript-eslint/[email protected](@typescript-eslint/[email protected])([email protected])([email protected]):
+  
/@typescript-eslint/[email protected](@typescript-eslint/[email protected])([email protected])([email protected]):
     resolution: {integrity: 
sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
@@ -3945,10 +3408,10 @@ packages:
         optional: true
     dependencies:
       '@eslint-community/regexpp': 4.10.0
-      '@typescript-eslint/parser': 6.11.0([email protected])([email protected])
+      '@typescript-eslint/parser': 6.11.0([email protected])([email protected])
       '@typescript-eslint/scope-manager': 6.11.0
-      '@typescript-eslint/type-utils': 6.11.0([email protected])([email protected])
-      '@typescript-eslint/utils': 6.11.0([email protected])([email protected])
+      '@typescript-eslint/type-utils': 6.11.0([email protected])([email protected])
+      '@typescript-eslint/utils': 6.11.0([email protected])([email protected])
       '@typescript-eslint/visitor-keys': 6.11.0
       debug: 4.3.4
       eslint: 8.53.0
@@ -3956,8 +3419,8 @@ packages:
       ignore: 5.2.4
       natural-compare: 1.4.0
       semver: 7.5.4
-      ts-api-utils: 1.0.3([email protected])
-      typescript: 5.5.4
+      ts-api-utils: 1.0.3([email protected])
+      typescript: 4.9.5
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -4014,27 +3477,6 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/[email protected]([email protected])([email protected]):
-    resolution: {integrity: 
sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/scope-manager': 6.11.0
-      '@typescript-eslint/types': 6.11.0
-      '@typescript-eslint/typescript-estree': 6.11.0([email protected])
-      '@typescript-eslint/visitor-keys': 6.11.0
-      debug: 4.3.4
-      eslint: 8.53.0
-      typescript: 5.5.4
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/[email protected]:
     resolution: {integrity: 
sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -4089,26 +3531,6 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/[email protected]([email protected])([email protected]):
-    resolution: {integrity: 
sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/typescript-estree': 6.11.0([email protected])
-      '@typescript-eslint/utils': 6.11.0([email protected])([email protected])
-      debug: 4.3.4
-      eslint: 8.53.0
-      ts-api-utils: 1.0.3([email protected])
-      typescript: 5.5.4
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/[email protected]:
     resolution: {integrity: 
sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -4159,27 +3581,6 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/[email protected]([email protected]):
-    resolution: {integrity: 
sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/types': 6.11.0
-      '@typescript-eslint/visitor-keys': 6.11.0
-      debug: 4.3.4
-      globby: 11.1.0
-      is-glob: 4.0.3
-      semver: 7.5.4
-      ts-api-utils: 1.0.3([email protected])
-      typescript: 5.5.4
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/[email protected]([email protected])([email protected]):
     resolution: {integrity: 
sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -4216,25 +3617,6 @@ packages:
       - typescript
     dev: true
 
-  /@typescript-eslint/[email protected]([email protected])([email protected]):
-    resolution: {integrity: 
sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
-    dependencies:
-      '@eslint-community/eslint-utils': 4.4.0([email protected])
-      '@types/json-schema': 7.0.15
-      '@types/semver': 7.5.5
-      '@typescript-eslint/scope-manager': 6.11.0
-      '@typescript-eslint/types': 6.11.0
-      '@typescript-eslint/typescript-estree': 6.11.0([email protected])
-      eslint: 8.53.0
-      semver: 7.5.4
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-    dev: true
-
   /@typescript-eslint/[email protected]:
     resolution: {integrity: 
sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -4253,77 +3635,6 @@ packages:
   /@ungap/[email protected]:
     resolution: {integrity: 
sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
 
-  /@vitejs/[email protected]([email protected]):
-    resolution: {integrity: 
sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA==}
-    peerDependencies:
-      vite: ^4 || ^5
-    dependencies:
-      '@swc/core': 1.7.3
-      vite: 4.5.3(@types/[email protected])([email protected])
-    transitivePeerDependencies:
-      - '@swc/helpers'
-    dev: true
-
-  /@volar/[email protected]:
-    resolution: {integrity: 
sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==}
-    dependencies:
-      '@volar/source-map': 1.11.1
-    dev: true
-
-  /@volar/[email protected]:
-    resolution: {integrity: 
sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==}
-    dependencies:
-      muggle-string: 0.3.1
-    dev: true
-
-  /@volar/[email protected]:
-    resolution: {integrity: 
sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==}
-    dependencies:
-      '@volar/language-core': 1.11.1
-      path-browserify: 1.0.1
-    dev: true
-
-  /@vue/[email protected]:
-    resolution: {integrity: 
sha512-Z0izUf32+wAnQewjHu+pQf1yw00EGOmevl1kE+ljjjMe7oEfpQ+BI3/JNK7yMB4IrUsqLDmPecUrpj3mCP+yJQ==}
-    dependencies:
-      '@babel/parser': 7.25.0
-      '@vue/shared': 3.4.34
-      entities: 4.5.0
-      estree-walker: 2.0.2
-      source-map-js: 1.2.0
-    dev: true
-
-  /@vue/[email protected]:
-    resolution: {integrity: 
sha512-3PUOTS1h5cskdOJMExCu2TInXuM0j60DRPpSCJDqOCupCfUZCJoyQmKtRmA8EgDNZ5kcEE7vketamRZfrEuVDw==}
-    dependencies:
-      '@vue/compiler-core': 3.4.34
-      '@vue/shared': 3.4.34
-    dev: true
-
-  /@vue/[email protected]([email protected]):
-    resolution: {integrity: 
sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@volar/language-core': 1.11.1
-      '@volar/source-map': 1.11.1
-      '@vue/compiler-dom': 3.4.34
-      '@vue/shared': 3.4.34
-      computeds: 0.0.1
-      minimatch: 9.0.5
-      muggle-string: 0.3.1
-      path-browserify: 1.0.1
-      typescript: 5.5.4
-      vue-template-compiler: 2.7.16
-    dev: true
-
-  /@vue/[email protected]:
-    resolution: {integrity: 
sha512-x5LmiRLpRsd9KTjAB8MPKf0CDPMcuItjP0gbNqFCIgL1I8iYp4zglhj9w9FPCdIbHG2M91RVeIbArFfFTz9I3A==}
-    dev: true
-
   /@webassemblyjs/[email protected]:
     resolution: {integrity: 
sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==}
     dependencies:
@@ -5489,13 +4800,6 @@ packages:
     resolution: {integrity: 
sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
     engines: {node: '>= 12'}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
-    engines: {node: ^12.20.0 || >=14}
-    requiresBuild: true
-    dev: true
-    optional: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==}
 
@@ -5533,10 +4837,6 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
 
@@ -5929,10 +5229,6 @@ packages:
     resolution: {integrity: 
sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==}
     dev: false
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
     peerDependencies:
@@ -6302,11 +5598,6 @@ packages:
   /[email protected]:
     resolution: {integrity: 
sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==,
 tarball: https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
-    engines: {node: '>=0.12'}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
     dependencies:
@@ -6438,36 +5729,6 @@ packages:
       is-date-object: 1.0.5
       is-symbol: 1.0.4
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
-    optionalDependencies:
-      '@esbuild/android-arm': 0.18.20
-      '@esbuild/android-arm64': 0.18.20
-      '@esbuild/android-x64': 0.18.20
-      '@esbuild/darwin-arm64': 0.18.20
-      '@esbuild/darwin-x64': 0.18.20
-      '@esbuild/freebsd-arm64': 0.18.20
-      '@esbuild/freebsd-x64': 0.18.20
-      '@esbuild/linux-arm': 0.18.20
-      '@esbuild/linux-arm64': 0.18.20
-      '@esbuild/linux-ia32': 0.18.20
-      '@esbuild/linux-loong64': 0.18.20
-      '@esbuild/linux-mips64el': 0.18.20
-      '@esbuild/linux-ppc64': 0.18.20
-      '@esbuild/linux-riscv64': 0.18.20
-      '@esbuild/linux-s390x': 0.18.20
-      '@esbuild/linux-x64': 0.18.20
-      '@esbuild/netbsd-x64': 0.18.20
-      '@esbuild/openbsd-x64': 0.18.20
-      '@esbuild/sunos-x64': 0.18.20
-      '@esbuild/win32-arm64': 0.18.20
-      '@esbuild/win32-ia32': 0.18.20
-      '@esbuild/win32-x64': 0.18.20
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
     engines: {node: '>=6'}
@@ -6880,14 +6141,6 @@ packages:
     dependencies:
       eslint: 8.53.0
 
-  /[email protected]([email protected]):
-    resolution: {integrity: 
sha512-QK49YrBAo5CLNLseZ7sZgvgTy21E6NEw22eZqc4teZfH8pxV3yXc9XXOYfUI6JNpw7mfHNkAeWtBxrTyykB6HA==}
-    peerDependencies:
-      eslint: '>=7'
-    dependencies:
-      eslint: 8.53.0
-    dev: true
-
   /[email protected]([email protected]):
     resolution: {integrity: 
sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==}
     engines: {node: '>=4'}
@@ -7064,10 +6317,6 @@ packages:
   /[email protected]:
     resolution: {integrity: 
sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
     engines: {node: '>=0.10.0'}
@@ -7386,15 +6635,6 @@ packages:
       jsonfile: 6.1.0
       universalify: 2.0.0
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
-    engines: {node: '>=6 <7 || >=8'}
-    dependencies:
-      graceful-fs: 4.2.11
-      jsonfile: 4.0.0
-      universalify: 0.1.2
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
     engines: {node: '>=10'}
@@ -7861,11 +7101,6 @@ packages:
       parent-module: 1.0.1
       resolve-from: 4.0.0
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
-    engines: {node: '>=8'}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==}
     engines: {node: '>=8'}
@@ -8776,10 +8011,6 @@ packages:
       - ts-node
       - utf-8-validate
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
 
@@ -8872,12 +8103,6 @@ packages:
     engines: {node: '>=6'}
     hasBin: true
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
-    optionalDependencies:
-      graceful-fs: 4.2.11
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
     dependencies:
@@ -8930,10 +8155,6 @@ packages:
     resolution: {integrity: 
sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==}
     engines: {node: '>= 8'}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==}
 
@@ -9052,14 +8273,6 @@ packages:
     resolution: {integrity: 
sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==}
     dev: true
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
-    dev: true
-
-  /[email protected]:
-    resolution: {integrity: 
sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
 
@@ -9113,12 +8326,6 @@ packages:
     dependencies:
       sourcemap-codec: 1.4.8
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
-    dependencies:
-      '@jridgewell/sourcemap-codec': 1.5.0
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
     engines: {node: '>=8'}
@@ -9268,13 +8475,6 @@ packages:
     dependencies:
       brace-expansion: 2.0.1
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
-    engines: {node: '>=16 || 14 >=14.17'}
-    dependencies:
-      brace-expansion: 2.0.1
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
     engines: {node: '>= 6'}
@@ -9302,10 +8502,6 @@ packages:
   /[email protected]:
     resolution: {integrity: 
sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==}
     hasBin: true
@@ -9318,12 +8514,6 @@ packages:
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
     hasBin: true
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
-    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
-    hasBin: true
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
 
@@ -9664,10 +8854,6 @@ packages:
       no-case: 3.0.4
       tslib: 2.6.2
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
     engines: {node: '>=4'}
@@ -10449,15 +9635,6 @@ packages:
       picocolors: 1.0.0
       source-map-js: 1.0.2
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==}
-    engines: {node: ^10 || ^12 || >=14}
-    dependencies:
-      nanoid: 3.3.7
-      picocolors: 1.0.1
-      source-map-js: 1.2.0
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
     engines: {node: '>= 0.8.0'}
@@ -11164,13 +10341,6 @@ packages:
     resolution: {integrity: 
sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==}
     engines: {node: '>=10'}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==}
-    dependencies:
-      is-core-module: 2.10.0
-      path-parse: 1.0.7
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
     hasBin: true
@@ -11238,14 +10408,6 @@ packages:
     optionalDependencies:
       fsevents: 2.3.3
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
-    engines: {node: '>=14.18.0', npm: '>=8.0.0'}
-    hasBin: true
-    optionalDependencies:
-      fsevents: 2.3.3
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==}
     engines: {node: '>=12'}
@@ -11588,11 +10750,6 @@ packages:
     resolution: {integrity: 
sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
     engines: {node: '>=0.10.0'}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
-    engines: {node: '>=0.10.0'}
-    dev: true
-
   /[email protected]([email protected]):
     resolution: {integrity: 
sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==}
     engines: {node: '>= 12.13.0'}
@@ -12181,11 +11338,6 @@ packages:
     resolution: {integrity: 
sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
     engines: {node: '>=0.6'}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-KAB2lrSS48y91MzFPFuDg4hLbvDiyTjOVgaK7Erw+5AmZXNq4sFRVn8r6yxSLuNs15PaokrDRpS61ERY9uZOug==}
-    engines: {node: '>=10'}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==}
     engines: {node: '>=6'}
@@ -12223,15 +11375,6 @@ packages:
       typescript: 4.9.5
     dev: true
 
-  /[email protected]([email protected]):
-    resolution: {integrity: 
sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
-    engines: {node: '>=16.13.0'}
-    peerDependencies:
-      typescript: '>=4.2.0'
-    dependencies:
-      typescript: 5.5.4
-    dev: true
-
   /[email protected](@types/[email protected])([email protected]):
     resolution: {integrity: 
sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
     hasBin: true
@@ -12384,18 +11527,6 @@ packages:
     engines: {node: '>=4.2.0'}
     hasBin: true
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==}
-    engines: {node: '>=14.17'}
-    hasBin: true
-    dev: true
-
-  /[email protected]:
-    resolution: {integrity: 
sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
-    engines: {node: '>=14.17'}
-    hasBin: true
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
     dependencies:
@@ -12449,11 +11580,6 @@ packages:
     dependencies:
       crypto-random-string: 2.0.0
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
-    engines: {node: '>= 4.0.0'}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
     engines: {node: '>= 4.0.0'}
@@ -12563,101 +11689,15 @@ packages:
       spdx-expression-parse: 3.0.1
     dev: true
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==}
-    engines: {node: '>= 0.10'}
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
     engines: {node: '>= 0.8'}
 
-  
/[email protected](@types/[email protected])([email protected])([email protected])([email protected]):
-    resolution: {integrity: 
sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==}
-    engines: {node: ^14.18.0 || >=16.0.0}
-    peerDependencies:
-      typescript: '*'
-      vite: '*'
-    peerDependenciesMeta:
-      vite:
-        optional: true
-    dependencies:
-      '@microsoft/api-extractor': 7.43.0(@types/[email protected])
-      '@rollup/pluginutils': 5.1.0([email protected])
-      '@vue/language-core': 1.8.27([email protected])
-      debug: 4.3.4
-      kolorist: 1.8.0
-      magic-string: 0.30.11
-      typescript: 5.5.4
-      vite: 4.5.3(@types/[email protected])([email protected])
-      vue-tsc: 1.8.27([email protected])
-    transitivePeerDependencies:
-      - '@types/node'
-      - rollup
-      - supports-color
-    dev: true
-
-  /[email protected](@types/[email protected])([email protected]):
-    resolution: {integrity: 
sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==}
-    engines: {node: ^14.18.0 || >=16.0.0}
-    hasBin: true
-    peerDependencies:
-      '@types/node': '>= 14'
-      less: '*'
-      lightningcss: ^1.21.0
-      sass: '*'
-      stylus: '*'
-      sugarss: '*'
-      terser: ^5.4.0
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-      less:
-        optional: true
-      lightningcss:
-        optional: true
-      sass:
-        optional: true
-      stylus:
-        optional: true
-      sugarss:
-        optional: true
-      terser:
-        optional: true
-    dependencies:
-      '@types/node': 16.11.59
-      esbuild: 0.18.20
-      postcss: 8.4.40
-      rollup: 3.29.4
-      sass: 1.54.9
-    optionalDependencies:
-      fsevents: 2.3.3
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
     engines: {node: '>=0.10.0'}
     dev: false
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==}
-    dependencies:
-      de-indent: 1.0.2
-      he: 1.2.0
-    dev: true
-
-  /[email protected]([email protected]):
-    resolution: {integrity: 
sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==}
-    hasBin: true
-    peerDependencies:
-      typescript: '*'
-    dependencies:
-      '@volar/typescript': 1.11.1
-      '@vue/language-core': 1.8.27([email protected])
-      semver: 7.5.4
-      typescript: 5.5.4
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
     dependencies:
@@ -13294,18 +12334,6 @@ packages:
     resolution: {integrity: 
sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
     engines: {node: '>=10'}
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==}
-    engines: {node: '>=8.0.0'}
-    hasBin: true
-    dependencies:
-      lodash.get: 4.4.2
-      lodash.isequal: 4.5.0
-      validator: 13.12.0
-    optionalDependencies:
-      commander: 9.5.0
-    dev: true
-
   /[email protected]([email protected]):
     resolution: {integrity: 
sha512-h4F3WMqsZgvvaE0n3lThx4MM81Ls9xebjvrABNzf5+jb3/03YjNTSgZXeyrvXDArMeV9untvWXRw1tY+ntPYbA==}
     engines: {node: '>=12.7.0'}
diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts
index 41dc0fef..789109d2 100644
--- a/ui/src/common/interface.ts
+++ b/ui/src/common/interface.ts
@@ -735,3 +735,35 @@ export interface ReactionItem {
   tooltip: string;
   is_active: boolean;
 }
+
+export interface BadgeListItem {
+  id: string;
+  name: string;
+  icon: string;
+  award_count: number;
+  earned: boolean;
+  /** 1: bronze 2: silver 3:gold */
+  level: number;
+}
+
+export interface BadgeListGroupItem {
+  badges: BadgeListItem[];
+  group_name: string;
+}
+
+export interface BadgeInfo extends BadgeListItem {
+  description: string;
+  earned_count: number;
+  is_single: boolean;
+}
+
+export interface BadgeDetailListReq {
+  page: number;
+  page_size: number;
+  badge_id: string;
+}
+
+export interface BadgeDetailListRes {
+  count: number;
+  list: BadgeInfo[];
+}
diff --git a/ui/src/components/CardBadge/index.tsx 
b/ui/src/components/CardBadge/index.tsx
index 9251b38c..6fb4af7c 100644
--- a/ui/src/components/CardBadge/index.tsx
+++ b/ui/src/components/CardBadge/index.tsx
@@ -19,35 +19,59 @@
 import { useTranslation } from 'react-i18next';
 import { FC } from 'react';
 import { Card, Badge } from 'react-bootstrap';
+import { Link } from 'react-router-dom';
 
+import classnames from 'classnames';
+
+import { Icon } from '@/components';
+import * as Type from '@/common/interface';
 import { formatCount } from '@/utils';
 
 import './index.scss';
 
 interface IProps {
-  data: any;
-  badgePill: boolean;
+  data: Type.BadgeListItem;
   showAwardedCount?: boolean;
 }
 
-const Index: FC<IProps> = ({ data, badgePill, showAwardedCount = false }) => {
+const Index: FC<IProps> = ({ data, showAwardedCount = false }) => {
   const { t } = useTranslation('translation', { keyPrefix: 'badges' });
   console.log(data);
   return (
-    <Card className="text-center badge-card">
+    <Link className="card text-center badge-card" to={`/badges/${data.id}`}>
       <Card.Body>
-        <Badge pill={badgePill} bg="success" className="label">
-          0
-        </Badge>
-        <img src="" width={96} height={96} alt="" />
-        <h6 className="mb-0 mt-3 text-center">Nice Question</h6>
+        {data.earned && (
+          <Badge bg="success" className="label">
+            {t('earned')}
+          </Badge>
+        )}
+
+        {/* <Badge pill={badgePill} bg="success" className="label">
+          {showEarned ? t('earned') : data.award_count}
+        </Badge> */}
+        {data.icon.startsWith('http') ? (
+          <img src={data.icon} width={96} height={96} alt={data.name} />
+        ) : (
+          <Icon
+            name={data.icon}
+            size="96px"
+            className={classnames(
+              'lh-1',
+              data.level === 1 && 'bronze',
+              data.level === 2 && 'silver',
+              data.level === 3 && 'gold',
+            )}
+          />
+        )}
+
+        <h6 className="mb-0 mt-3 text-center">{data.name}</h6>
         {showAwardedCount && (
           <div className="small text-secondary">
-            {t('x_awarded', { number: formatCount(16) })}
+            {t('x_awarded', { number: formatCount(data.award_count) })}
           </div>
         )}
       </Card.Body>
-    </Card>
+    </Link>
   );
 };
 
diff --git a/ui/src/index.scss b/ui/src/index.scss
index b174fbc5..6d3ade05 100644
--- a/ui/src/index.scss
+++ b/ui/src/index.scss
@@ -352,3 +352,13 @@ img[src=""] {
 .alert-exist {
   color: var(--an-alert-exist-color);
 }
+
+.bronze {
+  color: #CD7F32;
+}
+.silver {
+  color: #C0C0C0;
+}
+.gold {
+  color: #FFD700;
+}
diff --git a/ui/src/pages/Badges/Detail/components/Badge/index.tsx 
b/ui/src/pages/Badges/Detail/components/Badge/index.tsx
new file mode 100644
index 00000000..1fc5d43d
--- /dev/null
+++ b/ui/src/pages/Badges/Detail/components/Badge/index.tsx
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { FC } from 'react';
+import { Card, Badge } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import classnames from 'classnames';
+
+import * as Type from '@/common/interface';
+import { Icon } from '@/components';
+import { formatCount } from '@/utils';
+
+interface IProps {
+  data: Type.BadgeInfo;
+}
+
+const Index: FC<IProps> = ({ data }) => {
+  const { t } = useTranslation('translation', { keyPrefix: 'badges' });
+
+  if (!data?.id) {
+    return null;
+  }
+
+  return (
+    <Card className="mb-4">
+      <Card.Body className="d-flex">
+        {data.icon?.startsWith('http') ? (
+          <img
+            src={data.icon}
+            width={96}
+            height={96}
+            alt={data.name}
+            className="me-3"
+          />
+        ) : (
+          <Icon
+            name={data?.icon}
+            size="96px"
+            className={classnames(
+              'lh-1 me-3',
+              data?.level === 1 && 'bronze',
+              data?.level === 2 && 'silver',
+              data?.level === 3 && 'gold',
+            )}
+          />
+        )}
+        <div>
+          <h5>{data.name}</h5>
+          <div dangerouslySetInnerHTML={{ __html: data.description || '' }} />
+
+          {!data.is_single && (
+            <div className="mt-2">{t('can_earn_multiple')}</div>
+          )}
+
+          {data.award_count > 0 && data.earned_count > 0 && (
+            <div className="small mt-2">
+              {data.award_count > 0 && (
+                <span className="text-secondary">
+                  {t('x_awarded', { number: formatCount(data.award_count) })}
+                </span>
+              )}
+
+              {data.earned_count > 0 && (
+                <Badge bg="success" className="ms-2">
+                  {t('earned_x', { number: data.earned_count })}
+                </Badge>
+              )}
+            </div>
+          )}
+        </div>
+      </Card.Body>
+    </Card>
+  );
+};
+
+export default Index;
diff --git a/ui/src/pages/Badges/index.tsx 
b/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx
similarity index 56%
copy from ui/src/pages/Badges/index.tsx
copy to ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx
index 84784c53..df0c9204 100644
--- a/ui/src/pages/Badges/index.tsx
+++ b/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx
@@ -17,28 +17,32 @@
  * under the License.
  */
 
-import { useTranslation } from 'react-i18next';
-
-import { CardBadge } from '@/components';
-import { usePageTags } from '@/hooks';
+import { Card } from 'react-bootstrap';
 
 const Index = () => {
-  const { t } = useTranslation('translation', { keyPrefix: 'badges' });
+  return (
+    <Card className="mb-4 placeholder-glow">
+      <Card.Body className="d-flex">
+        <div
+          className="placeholder me-3"
+          style={{ width: '96px', height: '96px' }}
+        />
 
-  usePageTags({
-    title: t('title'),
-  });
+        <div>
+          <div className="placeholder h5" />
+          <div className="placeholder" />
+          <div className="placeholder" />
 
-  return (
-    <div className="pt-4 mb-5">
-      <h3 className="mb-4">{t('title')}</h3>
-      <h5 className="mb-4">Community Badges</h5>
-      <div className="d-flex flex-wrap" style={{ margin: '-12px' }}>
-        {[0, 1, 2, 3, 4, 5, 6].map((item) => {
-          return <CardBadge data={item} badgePill={false} />;
-        })}
-      </div>
-    </div>
+          <div className="placeholder mt-2 w-50" />
+
+          <div className="small mt-2">
+            <span className="placeholder" style={{ width: '100px' }} />
+
+            <span className="placeholder ms-2" style={{ width: '100px' }} />
+          </div>
+        </div>
+      </Card.Body>
+    </Card>
   );
 };
 
diff --git a/ui/src/pages/Badges/Detail/components/Loader/index.tsx 
b/ui/src/pages/Badges/Detail/components/Loader/index.tsx
new file mode 100644
index 00000000..515e69af
--- /dev/null
+++ b/ui/src/pages/Badges/Detail/components/Loader/index.tsx
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { FC, memo } from 'react';
+import { Col } from 'react-bootstrap';
+
+interface Props {
+  count?: number;
+}
+
+const Index: FC<Props> = ({ count = 12 }) => {
+  const list = new Array(count).fill(0).map((v, i) => v + i);
+  return (
+    <>
+      {list.map((v) => (
+        <Col sm={12} md={6} lg={3} key={v} className="mb-4 placeholder-glow">
+          <div className="small mb-1 placeholder" style={{ width: '100px' }} />
+          <div className="d-flex align-items-center">
+            <div
+              style={{ width: '40px', height: '40px' }}
+              className="placeholder rounded flex-shrink-0"
+            />
+            <div className="small ms-2">
+              <div className="placeholder lh-1" style={{ width: '80px' }} />
+              <div
+                className="text-secondary placeholder"
+                style={{ width: '150px' }}
+              />
+            </div>
+          </div>
+          <div className="mt-1 d-block placeholder" />
+          <div className="mt-1 d-block placeholder" />
+        </Col>
+      ))}
+    </>
+  );
+};
+
+export default memo(Index);
diff --git a/ui/src/pages/Badges/Detail/index.tsx 
b/ui/src/pages/Badges/Detail/index.tsx
index 7a192a13..3e8513ae 100644
--- a/ui/src/pages/Badges/Detail/index.tsx
+++ b/ui/src/pages/Badges/Detail/index.tsx
@@ -17,79 +17,98 @@
  * under the License.
  */
 
-import { Card, Badge, Row, Col } from 'react-bootstrap';
+import { Row, Col } from 'react-bootstrap';
 import { useTranslation } from 'react-i18next';
-import { Link } from 'react-router-dom';
+import { Link, useParams, useSearchParams } from 'react-router-dom';
 
-import { Avatar, FormatTime } from '@/components';
-import { usePageTags } from '@/hooks';
-import { formatCount } from '@/utils';
+// import classnames from 'classnames';
+
+import { Avatar, FormatTime, Pagination, Empty } from '@/components';
+import { usePageTags, useSkeletonControl } from '@/hooks';
+// import { formatCount } from '@/utils';
+import { useGetBadgeInfo, useBadgeDetailList } from '@/services';
+
+import BadgeDetail from './components/Badge';
+import Loader from './components/Loader';
+import HeaderLoader from './components/HeaderLoader';
 
 const Index = () => {
   const { t } = useTranslation('translation', { keyPrefix: 'badges' });
 
+  const { badge_id = '' } = useParams();
+  const [urlSearchParams] = useSearchParams();
+
+  const page = Number(urlSearchParams.get('page')) || 1;
+  const pageSize = 30;
+  const { data: badgeInfo, isLoading: isHeaderLoading } =
+    useGetBadgeInfo(badge_id);
+  const { data: badges, isLoading: isDetailLoading } = useBadgeDetailList({
+    badge_id,
+    page,
+    page_size: pageSize,
+  });
+
+  const { isSkeletonShow } = useSkeletonControl(isDetailLoading);
+
   usePageTags({
-    title: t('title'),
+    title: badgeInfo?.name || '',
   });
 
+  if (badgeInfo === undefined) {
+    return null;
+  }
+
+  console.log(badges);
+
   return (
     <div className="pt-4 mb-5">
       <h3 className="mb-4">{t('title')}</h3>
-      <Card className="mb-4">
-        <Card.Body className="d-flex">
-          <img src="" alt="" width={96} height={96} />
-          <div>
-            <h5>Support Expert</h5>
-            <div className="mb-2">
-              This badge is granted for achieving the expert level of our
-              community support programme. This certifies that the recipient 
has
-              demonstrated a high level of skills and abilities to manage and
-              support multiple communities/instances.
-            </div>
-            <div className="mb-2">{t('can_earn_multiple')}</div>
-            <div className="small">
-              <span className="text-secondary">
-                {t('x_awarded', { number: formatCount(16) })}
-              </span>
-              <Badge bg="success" className="ms-2">
-                {t('earned_x', { number: 2 })}
-              </Badge>
-            </div>
-          </div>
-        </Card.Body>
-      </Card>
+      {isHeaderLoading ? <HeaderLoader /> : <BadgeDetail data={badgeInfo} />}
       <Row>
-        {[0, 1, 2, 3, 4, 5, 6].map((item) => {
-          return (
-            <Col sm={12} md={6} lg={3} key={item} className="mb-4">
-              <FormatTime
-                time={1722397094672}
-                preFix={t('awarded')}
-                className="small mb-1 d-block"
-              />
-              <div className="d-flex align-items-center">
-                <Link to="/user">
-                  <Avatar size="40px" avatar="" alt="" />
-                </Link>
-                <div className="small ms-2">
-                  <Link
-                    to="/user"
-                    className="lh-1 name-ellipsis"
-                    style={{ maxWidth: '200px' }}>
-                    username
+        <Loader />
+        {isSkeletonShow ? (
+          <Loader />
+        ) : (
+          badges?.list?.map((item) => {
+            return (
+              <Col sm={12} md={6} lg={3} key={item.id} className="mb-4">
+                <FormatTime
+                  time={1722397094672}
+                  preFix={t('awarded')}
+                  className="small mb-1 d-block"
+                />
+                <div className="d-flex align-items-center">
+                  <Link to="/user">
+                    <Avatar size="40px" avatar="" alt="" />
                   </Link>
-                  <div className="text-secondary">
-                    980 {t('x_reputation', { keyPrefix: 'personal' })}
+                  <div className="small ms-2">
+                    <Link
+                      to="/user"
+                      className="lh-1 name-ellipsis"
+                      style={{ maxWidth: '200px' }}>
+                      username
+                    </Link>
+                    <div className="text-secondary">
+                      980 {t('x_reputation', { keyPrefix: 'personal' })}
+                    </div>
                   </div>
                 </div>
-              </div>
-              <Link to="/question" className="mt-1 d-block">
-                How to `go test` all tests in my project?
-              </Link>
-            </Col>
-          );
-        })}
+                <Link to="/question" className="mt-1 d-block">
+                  How to `go test` all tests in my project?
+                </Link>
+              </Col>
+            );
+          })
+        )}
       </Row>
+      {Number(badges?.count) <= 0 && !isDetailLoading && <Empty />}
+      <div className="d-flex justify-content-center">
+        <Pagination
+          currentPage={page}
+          pageSize={pageSize}
+          totalSize={badges?.count || 0}
+        />
+      </div>
     </div>
   );
 };
diff --git a/ui/src/pages/Badges/index.tsx b/ui/src/pages/Badges/index.tsx
index 84784c53..39628062 100644
--- a/ui/src/pages/Badges/index.tsx
+++ b/ui/src/pages/Badges/index.tsx
@@ -21,10 +21,13 @@ import { useTranslation } from 'react-i18next';
 
 import { CardBadge } from '@/components';
 import { usePageTags } from '@/hooks';
+import { useGetAllBadges } from '@/services';
 
 const Index = () => {
   const { t } = useTranslation('translation', { keyPrefix: 'badges' });
 
+  const { data: badgesList } = useGetAllBadges();
+
   usePageTags({
     title: t('title'),
   });
@@ -32,12 +35,18 @@ const Index = () => {
   return (
     <div className="pt-4 mb-5">
       <h3 className="mb-4">{t('title')}</h3>
-      <h5 className="mb-4">Community Badges</h5>
-      <div className="d-flex flex-wrap" style={{ margin: '-12px' }}>
-        {[0, 1, 2, 3, 4, 5, 6].map((item) => {
-          return <CardBadge data={item} badgePill={false} />;
-        })}
-      </div>
+      {badgesList?.map((item) => {
+        return (
+          <div key={item.group_name} className="mb-5">
+            <h5 className="mb-4">{item.group_name}</h5>
+            <div className="d-flex flex-wrap" style={{ margin: '-12px' }}>
+              {item.badges?.map((badge) => {
+                return <CardBadge data={badge} key={badge.id} />;
+              })}
+            </div>
+          </div>
+        );
+      })}
     </div>
   );
 };
diff --git a/ui/src/pages/Users/Personal/components/Badges/index.tsx 
b/ui/src/pages/Users/Personal/components/Badges/index.tsx
index a7bd3e58..0ef00f39 100644
--- a/ui/src/pages/Users/Personal/components/Badges/index.tsx
+++ b/ui/src/pages/Users/Personal/components/Badges/index.tsx
@@ -19,10 +19,11 @@
 
 import { FC } from 'react';
 
+import * as Type from '@/common/interface';
 import { CardBadge } from '@/components';
 
 interface IProps {
-  data: any[];
+  data: Type.BadgeListItem[];
   visible: boolean;
 }
 
@@ -33,8 +34,8 @@ const Index: FC<IProps> = ({ data, visible }) => {
   }
   return (
     <div className="d-flex flex-wrap" style={{ margin: '-12px' }}>
-      {[0, 1, 2, 3, 4, 5, 6].map((item) => {
-        return <CardBadge data={item} badgePill />;
+      {data.map((item) => {
+        return <CardBadge data={item} />;
       })}
     </div>
   );
diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx 
b/ui/src/pages/Users/Personal/components/Overview/index.tsx
index 384689dc..b4dd548b 100644
--- a/ui/src/pages/Users/Personal/components/Overview/index.tsx
+++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx
@@ -21,7 +21,8 @@ import { FC, memo } from 'react';
 import { useTranslation } from 'react-i18next';
 import { Row, Col } from 'react-bootstrap';
 
-import { CardBadge } from '@/components';
+// import * as Type from '@/common/interface';
+// import { CardBadge } from '@/components';
 import TopList from '../TopList';
 
 interface Props {
@@ -67,11 +68,11 @@ const Index: FC<Props> = ({ visible, introduction, data }) 
=> {
 
       <div className="mb-5">
         <h5 className="mb-3">{t('recent_badges')}</h5>
-        <div className="d-flex flex-wrap" style={{ margin: '-12px' }}>
+        {/* <div className="d-flex flex-wrap" style={{ margin: '-12px' }}>
           {[0, 1, 2, 3, 4, 5, 6].map((item) => {
             return <CardBadge data={item} badgePill />;
           })}
-        </div>
+        </div> */}
       </div>
     </div>
   );
diff --git a/ui/src/services/client/badges.ts b/ui/src/services/client/badges.ts
new file mode 100644
index 00000000..c3a7bba2
--- /dev/null
+++ b/ui/src/services/client/badges.ts
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import useSWR from 'swr';
+import qs from 'qs';
+
+import request from '@/utils/request';
+import type * as Type from '@/common/interface';
+
+export const useGetAllBadges = () => {
+  const apiUrl = '/answer/api/v1/badges';
+  const { data, error, mutate } = useSWR<Array<Type.BadgeListGroupItem>, 
Error>(
+    apiUrl,
+    request.instance.get,
+  );
+  return {
+    data,
+    isLoading: !data && !error,
+    error,
+    mutate,
+  };
+};
+
+export const useGetBadgeInfo = (id: string) => {
+  const { data, error, mutate } = useSWR<Type.BadgeInfo, Error>(
+    `/answer/api/v1/badge?id=${id}`,
+    request.instance.get,
+  );
+  return {
+    data,
+    isLoading: !data && !error,
+    error,
+    mutate,
+  };
+};
+
+export const useBadgeDetailList = (params: Type.BadgeDetailListReq) => {
+  const { data, error, mutate } = useSWR<Type.BadgeDetailListRes, Error>(
+    `/answer/api/v1/badge/awards/page?${qs.stringify(params)}`,
+    request.instance.get,
+  );
+  return {
+    data,
+    isLoading: !data && !error,
+    error,
+    mutate,
+  };
+};
diff --git a/ui/src/services/client/index.ts b/ui/src/services/client/index.ts
index 0d718423..005bc26d 100644
--- a/ui/src/services/client/index.ts
+++ b/ui/src/services/client/index.ts
@@ -30,3 +30,4 @@ export * from './revision';
 export * from './user';
 export * from './Oauth';
 export * from './review';
+export * from './badges';

Reply via email to