From 872c73d574dd834ea925ca9aeeb02879d20f5e64 Mon Sep 17 00:00:00 2001
From: waynelwz <100347187+waynelwz@users.noreply.github.com>
Date: Wed, 31 Aug 2022 15:58:49 +0800
Subject: [PATCH] feat: refector dataset/eva by datastore api (#1055)
* wip: datastore summary
* feat: project card with stats
* feat: eva table with store summary
* fix: dag lab of reaflow erros & new eva overview
* update: move project fetching to api header
* fix: lint erros
* fix: eslint error
* feat: new link ui
* optimize: text ellis of links
* optimize: overview & accordin ui
1. fix lazylog error when empty
* feat: user avator
* wip: binarylable heatmap
* feat: eva result based on datastore
* fix: eslint error
---
console/.eslintrc.js | 1 +
console/package.json | 3 +-
console/pnpm-lock.yaml | 257 +++++++++++-
console/src/api/ApiHeader.tsx | 24 +-
.../src/components/Accordion/Accordion.tsx | 3 +
console/src/components/Avatar/index.tsx | 31 ++
console/src/components/BaseSidebar.tsx | 50 ++-
.../BusyLoaderWrapper/BusyPlaceholder.tsx | 4 +-
console/src/components/Header/index.tsx | 143 +++++--
console/src/components/IconFont/index.tsx | 2 +-
console/src/components/Indicator/utils.ts | 51 ++-
console/src/components/Link/ButtonLink.tsx | 37 ++
console/src/components/Link/IconLink.tsx | 34 ++
console/src/components/Link/Link.tsx | 39 ++
console/src/components/Link/TextLink.tsx | 37 ++
console/src/components/Link/index.ts | 4 +
console/src/components/Table/TableNormal.tsx | 10 +-
console/src/components/Table/TableTyped.tsx | 26 +-
console/src/components/Table/index.tsx | 8 +-
.../data-table/data-custom-table.tsx | 4 +-
.../src/components/data-table/header-cell.tsx | 6 +-
.../data-table/measure-column-widths.tsx | 1 -
.../components/data-table/storeContext.tsx | 42 ++
.../datastore/hooks/useParseDatastore.ts | 41 ++
console/src/domain/datastore/utils.ts | 33 +-
.../domain/project/hooks/useFetchProject.ts | 3 +-
.../src/domain/project/schemas/project.tsx | 6 +
console/src/domain/user/schemas/user.tsx | 1 +
console/src/i18n/locales.ts | 9 +-
console/src/main.tsx | 7 +-
console/src/pages/Dataset/DatasetListCard.tsx | 26 +-
.../pages/Dataset/DatasetOverviewLayout.tsx | 2 +
.../pages/Dataset/DatasetVersionLayout.tsx | 12 +-
.../pages/Dataset/DatasetVersionListCard.tsx | 25 +-
.../src/pages/Evaluation/EvaluationLayout.tsx | 9 +-
.../pages/Evaluation/EvaluationListCard.tsx | 89 ++---
.../Evaluation/EvaluationListCompare.tsx | 39 +-
.../Evaluation/EvaluationOverviewLayout.tsx | 172 ++++----
.../pages/Evaluation/EvaluationResults.tsx | 62 ++-
console/src/pages/Job/JobDAG.tsx | 3 -
console/src/pages/Job/JobLayout.tsx | 10 +-
console/src/pages/Job/JobListCard.tsx | 11 +-
console/src/pages/Job/JobTasks.tsx | 12 +-
console/src/pages/Model/ModelLayout.tsx | 79 +++-
console/src/pages/Model/ModelListCard.tsx | 13 +-
.../src/pages/Model/ModelVersionLayout.tsx | 11 +-
console/src/pages/Model/Overview.tsx | 60 +--
console/src/pages/Project/Overview.tsx | 10 +-
console/src/pages/Project/ProjectListCard.tsx | 268 ++++++++-----
console/src/pages/Runtime/RuntimeLayout.tsx | 10 +-
console/src/pages/Runtime/RuntimeListCard.tsx | 11 +-
.../pages/Runtime/RuntimeVersionLayout.tsx | 11 +-
console/src/routes.tsx | 374 +++++++++---------
console/vite.config.ts | 2 +-
54 files changed, 1476 insertions(+), 762 deletions(-)
create mode 100644 console/src/components/Avatar/index.tsx
create mode 100644 console/src/components/Link/ButtonLink.tsx
create mode 100644 console/src/components/Link/IconLink.tsx
create mode 100644 console/src/components/Link/Link.tsx
create mode 100644 console/src/components/Link/TextLink.tsx
create mode 100644 console/src/components/Link/index.ts
create mode 100644 console/src/components/data-table/storeContext.tsx
create mode 100644 console/src/domain/datastore/hooks/useParseDatastore.ts
diff --git a/console/.eslintrc.js b/console/.eslintrc.js
index ee7fcfeff3..9faa40002b 100644
--- a/console/.eslintrc.js
+++ b/console/.eslintrc.js
@@ -76,6 +76,7 @@ module.exports = {
'react/jsx-one-expression-per-line': 'off',
'react/jsx-wrap-multilines': 'off',
'react/no-array-index-key': 'off',
+ 'react/jsx-props-no-spreading': 'off',
'react/require-default-props': [
'error',
{
diff --git a/console/package.json b/console/package.json
index e002fc16a2..c898e40170 100644
--- a/console/package.json
+++ b/console/package.json
@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@aksel/structjs": "^1.0.0",
"@faker-js/faker": "^6.3.1",
"@monaco-editor/react": "^4.3.1",
"@papercups-io/chat-widget": "^1.3.1",
@@ -105,7 +106,7 @@
"xterm": "^4.14.1",
"xterm-addon-fit": "^0.5.0",
"xterm-addon-web-links": "^0.4.0",
- "zustand": "^4.0.0-rc.1"
+ "zustand": "v4.1.1"
},
"scripts": {
"typecheck": "tsc --noEmit -p ./tsconfig.json",
diff --git a/console/pnpm-lock.yaml b/console/pnpm-lock.yaml
index d14fef9c56..0d2921fcb0 100644
--- a/console/pnpm-lock.yaml
+++ b/console/pnpm-lock.yaml
@@ -17,6 +17,7 @@ overrides:
react-virtualized: git+https://git@github.com/remorses/react-virtualized-fixed-import.git#9.22.3
specifiers:
+ '@aksel/structjs': ^1.0.0
'@babel/core': '>=7.13.0 <8.0.0'
'@faker-js/faker': ^6.3.1
'@mdx-js/react': ^2.1.3
@@ -171,9 +172,10 @@ specifiers:
xterm: ^4.14.1
xterm-addon-fit: ^0.5.0
xterm-addon-web-links: ^0.4.0
- zustand: ^4.0.0-rc.1
+ zustand: v4.1.1
dependencies:
+ '@aksel/structjs': 1.0.0
'@faker-js/faker': 6.3.1
'@monaco-editor/react': 4.4.5_gnpkoj5uzrqs5wqxh42z7ffyam
'@papercups-io/chat-widget': 1.3.1_sfoxds7t5ydpegc3knd667wn6m
@@ -276,7 +278,7 @@ dependencies:
xterm: 4.19.0
xterm-addon-fit: 0.5.0_xterm@4.19.0
xterm-addon-web-links: 0.4.0_xterm@4.19.0
- zustand: 4.0.0_immer@9.0.15+react@17.0.2
+ zustand: 4.1.1_immer@9.0.15+react@17.0.2
devDependencies:
'@babel/core': 7.18.10
@@ -338,6 +340,12 @@ packages:
resolution: {integrity: sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==}
dev: false
+ /@aksel/structjs/1.0.0:
+ resolution: {integrity: sha512-7BuOlCj7bS09Gr/uJFrKJVWaZqTSOoK2eUuqUebAZq5cALZP6eNz5K5cbprYNX6KBFGMnR+CeSmZk/DjVo3ecg==}
+ dependencies:
+ npm-name: 5.5.0
+ dev: false
+
/@ampproject/remapping/2.2.0:
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
engines: {node: '>=6.0.0'}
@@ -3205,6 +3213,11 @@ packages:
resolution: {integrity: sha512-K7C7IlQ3zLePEZleUN21ceBA2aLcMnLHTLph8QWk1JK37L90obdpY+QGY8bXMKxf1ht1Z0MNewvXxWv0oGDYFg==}
dev: true
+ /@sindresorhus/is/0.14.0:
+ resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==}
+ engines: {node: '>=6'}
+ dev: false
+
/@sinonjs/commons/1.8.3:
resolution: {integrity: sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==}
dependencies:
@@ -4946,6 +4959,13 @@ packages:
- supports-color
dev: true
+ /@szmarczak/http-timer/1.1.2:
+ resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==}
+ engines: {node: '>=6'}
+ dependencies:
+ defer-to-connect: 1.1.3
+ dev: false
+
/@testing-library/dom/7.31.2:
resolution: {integrity: sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==}
engines: {node: '>=10'}
@@ -5350,6 +5370,12 @@ packages:
/@types/json5/0.0.29:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+ /@types/keyv/3.1.4:
+ resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
+ dependencies:
+ '@types/node': 18.6.5
+ dev: false
+
/@types/lodash/4.14.182:
resolution: {integrity: sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==}
@@ -5519,6 +5545,12 @@ packages:
'@types/node': 18.6.5
dev: true
+ /@types/responselike/1.0.0:
+ resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
+ dependencies:
+ '@types/node': 18.6.5
+ dev: false
+
/@types/retry/0.12.0:
resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==}
dev: true
@@ -7565,6 +7597,10 @@ packages:
resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==}
dev: true
+ /builtins/1.0.3:
+ resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==}
+ dev: false
+
/bytes/3.0.0:
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
engines: {node: '>= 0.8'}
@@ -7655,6 +7691,19 @@ packages:
unset-value: 1.0.0
dev: true
+ /cacheable-request/6.1.0:
+ resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==}
+ engines: {node: '>=8'}
+ dependencies:
+ clone-response: 1.0.3
+ get-stream: 5.2.0
+ http-cache-semantics: 4.1.0
+ keyv: 3.1.0
+ lowercase-keys: 2.0.0
+ normalize-url: 4.5.1
+ responselike: 1.0.2
+ dev: false
+
/cachedir/2.3.0:
resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==}
engines: {node: '>=6'}
@@ -7979,6 +8028,12 @@ packages:
shallow-clone: 3.0.1
dev: true
+ /clone-response/1.0.3:
+ resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
+ dependencies:
+ mimic-response: 1.0.1
+ dev: false
+
/clsx/1.1.0:
resolution: {integrity: sha512-3avwM37fSK5oP6M5rQ9CNe99lwxhXDOeSWVPAOYF6OazUTgZCMb0yWlJpmdD74REy1gkEaFiub2ULv4fq9GUhA==}
engines: {node: '>=6'}
@@ -9531,6 +9586,13 @@ packages:
resolution: {integrity: sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==}
engines: {node: '>=0.10'}
+ /decompress-response/3.3.0:
+ resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==}
+ engines: {node: '>=4'}
+ dependencies:
+ mimic-response: 1.0.1
+ dev: false
+
/dedent/0.7.0:
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
dev: true
@@ -9551,6 +9613,11 @@ packages:
regexp.prototype.flags: 1.4.3
dev: false
+ /deep-extend/0.6.0:
+ resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
+ engines: {node: '>=4.0.0'}
+ dev: false
+
/deep-is/0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -9583,6 +9650,10 @@ packages:
deep-copy: 1.4.2
dev: false
+ /defer-to-connect/1.1.3:
+ resolution: {integrity: sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==}
+ dev: false
+
/define-lazy-prop/2.0.0:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
engines: {node: '>=8'}
@@ -9940,6 +10011,10 @@ packages:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
dev: true
+ /duplexer3/0.1.5:
+ resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==}
+ dev: false
+
/duplexify/3.7.1:
resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
dependencies:
@@ -12104,14 +12179,12 @@ packages:
engines: {node: '>=6'}
dependencies:
pump: 3.0.0
- dev: true
/get-stream/5.2.0:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'}
dependencies:
pump: 3.0.0
- dev: true
/get-stream/6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
@@ -12418,6 +12491,25 @@ packages:
xtend: 4.0.2
dev: false
+ /got/9.6.0:
+ resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ '@sindresorhus/is': 0.14.0
+ '@szmarczak/http-timer': 1.1.2
+ '@types/keyv': 3.1.4
+ '@types/responselike': 1.0.0
+ cacheable-request: 6.1.0
+ decompress-response: 3.3.0
+ duplexer3: 0.1.5
+ get-stream: 4.1.0
+ lowercase-keys: 1.0.1
+ mimic-response: 1.0.1
+ p-cancelable: 1.1.0
+ to-readable-stream: 1.0.0
+ url-parse-lax: 3.0.0
+ dev: false
+
/graceful-fs/4.2.10:
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
@@ -12951,6 +13043,10 @@ packages:
entities: 2.2.0
dev: true
+ /http-cache-semantics/4.1.0:
+ resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==}
+ dev: false
+
/http-deceiver/1.2.7:
resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==}
dev: true
@@ -13227,7 +13323,6 @@ packages:
/ini/1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
- dev: true
/ini/2.0.0:
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
@@ -13277,6 +13372,11 @@ packages:
loose-envify: 1.4.0
dev: false
+ /ip-regex/4.3.0:
+ resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==}
+ engines: {node: '>=8'}
+ dev: false
+
/ip/2.0.0:
resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==}
dev: true
@@ -13650,6 +13750,13 @@ packages:
engines: {node: '>=6'}
dev: true
+ /is-scoped/2.1.0:
+ resolution: {integrity: sha512-Cv4OpPTHAK9kHYzkzCrof3VJh7H/PrG2MBUMvvJebaaUMbqhm0YAtXnvh0I3Hnj2tMZWwrRROWLSgfJrKqWmlQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ scoped-regex: 2.1.0
+ dev: false
+
/is-set/2.0.2:
resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
dev: true
@@ -13697,6 +13804,13 @@ packages:
engines: {node: '>=10'}
dev: true
+ /is-url-superb/3.0.0:
+ resolution: {integrity: sha512-3faQP+wHCGDQT1qReM5zCPx2mxoal6DzbzquFlCYJLWyy4WPTved33ea2xFbX37z4NoriEwZGIYhFtx8RUB5wQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ url-regex: 5.0.0
+ dev: false
+
/is-utf8/0.2.1:
resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==}
dev: true
@@ -14551,6 +14665,10 @@ packages:
engines: {node: '>=4'}
hasBin: true
+ /json-buffer/3.0.0:
+ resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==}
+ dev: false
+
/json-parse-better-errors/1.0.2:
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
dev: true
@@ -14757,6 +14875,12 @@ packages:
resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==}
dev: false
+ /keyv/3.1.0:
+ resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==}
+ dependencies:
+ json-buffer: 3.0.0
+ dev: false
+
/kind-of/3.2.2:
resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
engines: {node: '>=0.10.0'}
@@ -15014,6 +15138,10 @@ packages:
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
dev: true
+ /lodash.zip/4.2.0:
+ resolution: {integrity: sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==}
+ dev: false
+
/lodash/4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@@ -15069,6 +15197,16 @@ packages:
tslib: 2.4.0
dev: true
+ /lowercase-keys/1.0.1:
+ resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /lowercase-keys/2.0.0:
+ resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
+ engines: {node: '>=8'}
+ dev: false
+
/lowlight/1.12.1:
resolution: {integrity: sha512-OqaVxMGIESnawn+TU/QMV5BJLbUghUfjDWPAtFqDYDmDtr4FnB+op8xM+pR7nKlauHNUHXGt0VgWatFB8voS5w==}
dependencies:
@@ -15887,6 +16025,11 @@ packages:
engines: {node: '>=6'}
dev: true
+ /mimic-response/1.0.1:
+ resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
+ engines: {node: '>=4'}
+ dev: false
+
/min-document/2.19.0:
resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==}
dependencies:
@@ -16336,6 +16479,11 @@ packages:
svg-arc-to-cubic-bezier: 3.2.0
dev: false
+ /normalize-url/4.5.1:
+ resolution: {integrity: sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==}
+ engines: {node: '>=8'}
+ dev: false
+
/normalize-url/6.1.0:
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
engines: {node: '>=10'}
@@ -16349,6 +16497,19 @@ packages:
resolution: {integrity: sha512-5PDmaAsVfnWUgTUbJ3ERwn7u79Z0dYxN9ErxCpVJJqe2RK0PJ3z+iFUxuqjwtlDDegXvtWoxD/3Fzxox7tFGWA==}
dev: false
+ /npm-name/5.5.0:
+ resolution: {integrity: sha512-l7/uyVfEi2e3ho+ovaJZC0xlbwzXNUz3RxkxpfcnLuoGKAuYoo9YoJ/uy18PsTD8IziugGHks4t/mGmBJEZ4Qg==}
+ engines: {node: '>=8'}
+ dependencies:
+ got: 9.6.0
+ is-scoped: 2.1.0
+ is-url-superb: 3.0.0
+ lodash.zip: 4.2.0
+ registry-auth-token: 4.2.2
+ registry-url: 5.1.0
+ validate-npm-package-name: 3.0.0
+ dev: false
+
/npm-run-path/2.0.2:
resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
engines: {node: '>=4'}
@@ -16643,6 +16804,11 @@ packages:
p-map: 2.1.0
dev: true
+ /p-cancelable/1.1.0:
+ resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==}
+ engines: {node: '>=6'}
+ dev: false
+
/p-cancelable/3.0.0:
resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==}
engines: {node: '>=12.20'}
@@ -18042,6 +18208,11 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
+ /prepend-http/2.0.0:
+ resolution: {integrity: sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==}
+ engines: {node: '>=4'}
+ dev: false
+
/prettier-linter-helpers/1.0.0:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
engines: {node: '>=6.0.0'}
@@ -18255,7 +18426,6 @@ packages:
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
- dev: true
/pumpify/1.5.1:
resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==}
@@ -18477,6 +18647,16 @@ packages:
shallowequal: 1.1.0
dev: false
+ /rc/1.2.8:
+ resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
+ hasBin: true
+ dependencies:
+ deep-extend: 0.6.0
+ ini: 1.3.8
+ minimist: 1.2.6
+ strip-json-comments: 2.0.1
+ dev: false
+
/rdk/6.0.2_646vzgqebfewgbtcnhdqyrdafi:
resolution: {integrity: sha512-Q3nlhqboFdoigCCHIUZFDzAlRY6dTCfOi4zPuELLcbqUZ8cqFE6HK7KREBRqIo2WPmGrCmf+FW299j/0LAvJIA==}
peerDependencies:
@@ -19618,6 +19798,20 @@ packages:
unicode-match-property-value-ecmascript: 2.0.0
dev: true
+ /registry-auth-token/4.2.2:
+ resolution: {integrity: sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ rc: 1.2.8
+ dev: false
+
+ /registry-url/5.1.0:
+ resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==}
+ engines: {node: '>=8'}
+ dependencies:
+ rc: 1.2.8
+ dev: false
+
/regjsgen/0.6.0:
resolution: {integrity: sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==}
dev: true
@@ -20051,6 +20245,12 @@ packages:
supports-preserve-symlinks-flag: 1.0.0
dev: true
+ /responselike/1.0.2:
+ resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==}
+ dependencies:
+ lowercase-keys: 1.0.1
+ dev: false
+
/restore-cursor/3.1.0:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
@@ -20331,6 +20531,11 @@ packages:
ajv-keywords: 5.1.0_ajv@8.11.0
dev: true
+ /scoped-regex/2.1.0:
+ resolution: {integrity: sha512-g3WxHrqSWCZHGHlSrF51VXFdjImhwvH8ZO/pryFH56Qi0cDsZfylQa/t0jCzVQFNbNvM00HfHjkDPEuarKDSWQ==}
+ engines: {node: '>=8'}
+ dev: false
+
/screenfull/5.2.0:
resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==}
engines: {node: '>=0.10.0'}
@@ -21157,6 +21362,11 @@ packages:
dependencies:
min-indent: 1.0.1
+ /strip-json-comments/2.0.1:
+ resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
/strip-json-comments/3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@@ -21769,6 +21979,11 @@ packages:
resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==}
dev: false
+ /tlds/1.231.0:
+ resolution: {integrity: sha512-L7UQwueHSkGxZHQBXHVmXW64oi+uqNtzFt2x6Ssk7NVnpIbw16CRs4eb/jmKOZ9t2JnqZ/b3Cfvo97lnXqKrhw==}
+ hasBin: true
+ dev: false
+
/tmp/0.2.1:
resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
engines: {node: '>=8.17.0'}
@@ -21813,6 +22028,11 @@ packages:
parse-unit: 1.0.1
dev: false
+ /to-readable-stream/1.0.0:
+ resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==}
+ engines: {node: '>=6'}
+ dev: false
+
/to-regex-range/2.1.1:
resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==}
engines: {node: '>=0.10.0'}
@@ -22397,10 +22617,25 @@ packages:
webpack: 4.46.0
dev: true
+ /url-parse-lax/3.0.0:
+ resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ prepend-http: 2.0.0
+ dev: false
+
/url-polyfill/1.1.12:
resolution: {integrity: sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==}
dev: false
+ /url-regex/5.0.0:
+ resolution: {integrity: sha512-O08GjTiAFNsSlrUWfqF1jH0H1W3m35ZyadHrGv5krdnmPPoxP27oDTqux/579PtaroiSGm5yma6KT1mHFH6Y/g==}
+ engines: {node: '>=8'}
+ dependencies:
+ ip-regex: 4.3.0
+ tlds: 1.231.0
+ dev: false
+
/url/0.11.0:
resolution: {integrity: sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==}
dependencies:
@@ -22571,6 +22806,12 @@ packages:
spdx-expression-parse: 3.0.1
dev: true
+ /validate-npm-package-name/3.0.0:
+ resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==}
+ dependencies:
+ builtins: 1.0.3
+ dev: false
+
/validate.io-array-like/1.0.2:
resolution: {integrity: sha512-rGLiN0cvY9OWzQcWP+RtqZR/MK9RUz3gKDTCcRLtEQ/BvlanMF5PyqtVIN+CgrIBCv/ypfme9v7r4yMJPYpbNA==}
dependencies:
@@ -23565,8 +23806,8 @@ packages:
engines: {node: '>=10'}
dev: true
- /zustand/4.0.0_immer@9.0.15+react@17.0.2:
- resolution: {integrity: sha512-OrsfQTnRXF1LZ9/vR/IqN9ws5EXUhb149xmPjErZnUrkgxS/gAHGy2dPNIVkVvoxrVe1sIydn4JjF0dYHmGeeQ==}
+ /zustand/4.1.1_immer@9.0.15+react@17.0.2:
+ resolution: {integrity: sha512-h4F3WMqsZgvvaE0n3lThx4MM81Ls9xebjvrABNzf5+jb3/03YjNTSgZXeyrvXDArMeV9untvWXRw1tY+ntPYbA==}
engines: {node: '>=12.7.0'}
peerDependencies:
immer: '>=9.0'
diff --git a/console/src/api/ApiHeader.tsx b/console/src/api/ApiHeader.tsx
index 94055623c9..5f09ef8057 100644
--- a/console/src/api/ApiHeader.tsx
+++ b/console/src/api/ApiHeader.tsx
@@ -8,7 +8,9 @@ import { getErrMsg } from '@/api'
import { useLocation } from 'react-router-dom'
import useTranslation from '@/hooks/useTranslation'
import { useCurrentUserRoles } from '@/hooks/useCurrentUserRoles'
-import { useFirstRender } from '../hooks/useFirstRender'
+import { useFirstRender } from '@/hooks/useFirstRender'
+import { useProject } from '@project/hooks/useProject'
+import { useFetchProject } from '@/domain/project/hooks/useFetchProject'
export default function ApiHeader() {
const location = useLocation()
@@ -21,6 +23,11 @@ export default function ApiHeader() {
const [, setCurrentUserRoles] = useCurrentUserRoles()
const userRoles = useQuery('currentUserRoles', () => fetchCurrentUserRoles(), { enabled: false })
const [t] = useTranslation()
+ const projectId = React.useMemo(() => location?.pathname.match(/^\/projects\/(\d*)\/?/)?.[1], [location])
+ const projectInfo = useFetchProject(projectId)
+ const { setProject } = useProject()
+
+ // console.log(projectId, location, location?.pathname.match(/^\/projects\/(\d*)\/?/))
useFirstRender(() => {
axios.interceptors.response.use(
@@ -58,9 +65,10 @@ export default function ApiHeader() {
useEffect(() => {
if (currentUser) {
- // userRoles.refetch()
+ userRoles.refetch()
}
- }, [currentUser, userRoles])
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [currentUser])
useEffect(() => {
if (lastLocationPathRef.current !== location.pathname) {
@@ -70,8 +78,16 @@ export default function ApiHeader() {
}, [location.pathname])
useEffect(() => {
- setCurrentUserRoles(userRoles.data)
+ if (userRoles.data) {
+ setCurrentUserRoles(userRoles.data)
+ }
}, [userRoles.data, setCurrentUserRoles])
+ useEffect(() => {
+ if (projectInfo.data) {
+ setProject(projectInfo.data)
+ }
+ }, [projectInfo.data, setProject, projectId])
+
return <>>
}
diff --git a/console/src/components/Accordion/Accordion.tsx b/console/src/components/Accordion/Accordion.tsx
index 45d1aa88cf..ea6b1f55fc 100644
--- a/console/src/components/Accordion/Accordion.tsx
+++ b/console/src/components/Accordion/Accordion.tsx
@@ -22,6 +22,9 @@ export default function Accordion({ children, ...props }: IAccordionProps) {
Header: {
style: {
backgroundColor: '#F7F8FA',
+ paddingTop: '9px',
+ paddingBottom: '9px',
+ fontSize: '14px',
},
},
Content: {
diff --git a/console/src/components/Avatar/index.tsx b/console/src/components/Avatar/index.tsx
new file mode 100644
index 0000000000..3ada61006a
--- /dev/null
+++ b/console/src/components/Avatar/index.tsx
@@ -0,0 +1,31 @@
+import React from 'react'
+import { createUseStyles } from 'react-jss'
+import { StatefulTooltip } from 'baseui/tooltip'
+
+const useStyles = createUseStyles({
+ member: {
+ display: 'grid',
+ placeItems: 'center',
+ backgroundColor: '#8B9FC7',
+ borderRadius: '50%',
+ color: '#fff',
+ },
+})
+
+export default function Avatar({ name = '', size = 34, isTooltip = true }) {
+ const styles = useStyles()
+
+ return (
+
+
+ {name?.substr(0, 2)}
+
+
+ )
+}
diff --git a/console/src/components/BaseSidebar.tsx b/console/src/components/BaseSidebar.tsx
index 3b80f10a1b..884a03fc27 100644
--- a/console/src/components/BaseSidebar.tsx
+++ b/console/src/components/BaseSidebar.tsx
@@ -3,7 +3,7 @@
import { Navigation } from 'baseui/side-navigation'
import _ from 'lodash'
import React, { useCallback, useContext, useMemo } from 'react'
-import { useLocation, useHistory, Link } from 'react-router-dom'
+import { useLocation, useHistory } from 'react-router-dom'
import useSidebarWidth from '@/hooks/useSidebarWidth'
import { useStyletron } from 'baseui'
import type { IconBaseProps } from 'react-icons/lib'
@@ -11,6 +11,8 @@ import { SidebarContext } from '@/contexts/SidebarContext'
import Text from '@/components/Text'
import { createUseStyles } from 'react-jss'
import IconFont from '@/components/IconFont'
+import { StatefulTooltip } from 'baseui/tooltip'
+import TextLink from './Link/TextLink'
const useBaseSideBarStyles = createUseStyles({
sidebarWrapper: {
@@ -29,7 +31,7 @@ const useBaseSideBarStyles = createUseStyles({
backgroundColor: '#F7F8FA',
color: '#02102B',
display: 'flex',
- gap: 14,
+ gap: 8,
fontSize: '14px',
placeItems: 'center',
padding: '8px 26px 8px 26px',
@@ -98,8 +100,13 @@ export default function BaseSidebar({ navItems, style, title, icon, titleLink }:
justifyContent: ctx.expanded ? 'flex-start' : 'center',
}}
>
- {Icon}
+ {ctx.expanded && Icon}
{ctx.expanded && {item.title}}
+ {!ctx.expanded && (
+
+ {Icon}
+
+ )}
),
itemId: item.path,
@@ -146,26 +153,33 @@ export default function BaseSidebar({ navItems, style, title, icon, titleLink }:
}}
>
{title && icon && (
-
- {icon}
- {ctx.expanded && (
-
- {title}
-
- )}
-
+
+ {icon}
+
+
+ {ctx.expanded && (
+
+ {title}
+
+ )}
+
+
)}
-
+
>
)
@@ -28,7 +28,7 @@ export default function BusyPlaceholder({ type }: IBusyPlaceholderProps) {
children = (
<>
-
+
>
)
diff --git a/console/src/components/Header/index.tsx b/console/src/components/Header/index.tsx
index 62e07c1419..2d64f665c9 100644
--- a/console/src/components/Header/index.tsx
+++ b/console/src/components/Header/index.tsx
@@ -7,17 +7,19 @@ import useTranslation from '@/hooks/useTranslation'
import { createUseStyles } from 'react-jss'
import { IThemedStyleProps } from '@/theme'
import { useCurrentThemeType } from '@/hooks/useCurrentThemeType'
-import { BsChevronDown } from 'react-icons/bs'
-import { Link, useHistory } from 'react-router-dom'
+import { useHistory } from 'react-router-dom'
import PasswordForm from '@user/components/PasswordForm'
import { IChangePasswordSchema } from '@user/schemas/user'
import { changePassword } from '@user/services/user'
import { SidebarContext } from '@/contexts/SidebarContext'
import { toaster } from 'baseui/toast'
import { useCurrentUserRoles } from '@/hooks/useCurrentUserRoles'
+import { TextLink } from '@/components/Link'
+import classNames from 'classnames'
import { useAuth } from '@/api/Auth'
import IconFont from '../IconFont'
import Logo from './Logo'
+import Avatar from '../Avatar'
const useHeaderStyles = createUseStyles({
headerWrapper: {
@@ -114,11 +116,11 @@ const useStyles = createUseStyles({
'cursor': 'pointer',
'display': 'flex',
'align-items': 'center',
- 'min-width': '140px',
'height': '100%',
'margin-left': '12px',
'padding': '10px 0 10px 0',
'justifyContent': 'flex-end',
+ 'width': '220px',
'&:hover': {
'& $userMenu': {
@@ -138,11 +140,11 @@ const useStyles = createUseStyles({
'backgroundColor': '#264480',
},
userMenu: (props: IThemedStyleProps) => ({
+ 'padding': '16px 0px 0px',
'position': 'absolute',
'top': '100%',
'display': 'none',
'margin': 0,
- 'padding': '8px 0',
'line-height': 1.6,
'flex-direction': 'column',
'alignItems': 'center',
@@ -164,18 +166,69 @@ const useStyles = createUseStyles({
'text-decoration': 'none',
},
},
+ 'backgroundColor': '#FFF',
}),
+ userMenuItems: {
+ width: '100%',
+ display: 'flex',
+ flexShrink: 0,
+ flexDirection: 'column',
+ overflow: 'hidden',
+ overflowY: 'auto',
+ background: '#FFFFFF',
+ transition: 'all 200ms cubic-bezier(0.7, 0.1, 0.33, 1) 0ms',
+ color: 'rgba(2,16,43,0.60)',
+ borderRight: '1px solid #E2E7F0',
+ padding: '8px 12px 8px',
+ },
userMenuItem: (props: IThemedStyleProps) => ({
+ 'display': 'flex',
+ 'alignItems': 'center',
+ 'justifyContent': 'left',
+ 'alignSelf': 'normal',
+ 'gap': '10px',
+ 'height': '32px',
+ 'paddingLeft': '10px',
+ 'color': props.theme.colors.contentPrimary,
+ 'borderRadius': '4px',
+ '&:hover': {
+ backgroundColor: 'var(--color-brandMenuItemBackground)',
+ },
+ }),
+ userSignedIn: {
+ flex: 1,
+ color: 'rgba(2,16,43,0.40)',
+ textAlign: 'left',
+ width: '100%',
+ marginBottom: '13px',
+ padding: '0 12px',
+ },
+ userAvatar: {
+ flex: 1,
+ width: '100%',
+ paddingBottom: '17px',
+ gap: '13px',
+ display: 'grid',
+ gridTemplateColumns: '34px 1fr',
+ overflow: 'hidden',
+ padding: '0 12px',
+ },
+ userAvatarInfo: {
+ flex: 1,
display: 'flex',
+ flexDirection: 'row',
alignItems: 'center',
- justifyContent: 'left',
- alignSelf: 'normal',
- gap: '10px',
- height: '32px',
- paddingLeft: '10px',
- color: props.theme.colors.contentPrimary,
- backgroundColor: 'var(--color-brandMenuItemBackground)',
- }),
+ },
+ userAvatarName: {
+ fontSize: '14px',
+ lineHeight: '14px',
+ color: '#02102B',
+ },
+ userAvatarEmail: {
+ fontSize: '12px',
+ lineHeight: '12px',
+ color: 'rgba(2,16,43,0.60)',
+ },
roundWrapper: {
borderRadius: '50%',
backgroundColor: 'var(--color-brandWhite)',
@@ -185,6 +238,11 @@ const useStyles = createUseStyles({
alignItems: 'center',
justifyContent: 'center',
},
+ divider: {
+ height: '1px',
+ width: '100%',
+ backgroundColor: '#EEF1F6',
+ },
})
export default function Header() {
@@ -231,7 +289,9 @@ export default function Header() {
{currentUser && (
- {t('Project')}
+
+ {t('Project')}
+
)}
@@ -239,40 +299,51 @@ export default function Header() {
{currentUser && (
- {sysRole === 'OWNER' && (
+
{t('Signed in as')}
+
+
+
+
{currentUser.name}
+
{currentUser.email ?? ''}
+
+
+
+
+ {sysRole === 'OWNER' && (
+
{
+ history.push('/admin')
+ }}
+ >
+
+ {t('Admin Settings')}
+
+ )}
{
- history.push('/admin')
+ setIsChangePasswordOpen(true)
}}
>
-
- {t('Admin Settings')}
+
+ {t('Change Password')}
- )}
-
{
- setIsChangePasswordOpen(true)
- }}
- >
-
- {t('Change Password')}
-
diff --git a/console/src/components/IconFont/index.tsx b/console/src/components/IconFont/index.tsx
index 8a0ec1646f..7a210cb42f 100644
--- a/console/src/components/IconFont/index.tsx
+++ b/console/src/components/IconFont/index.tsx
@@ -97,7 +97,7 @@ export default function IconFont({ size = 14, type = 'user', kind = 'inherit', s
}}
>
{type in hijacked ? (
-
+
) : (
)}
diff --git a/console/src/components/Indicator/utils.ts b/console/src/components/Indicator/utils.ts
index 4ff7c17873..6dd4f7b15b 100644
--- a/console/src/components/Indicator/utils.ts
+++ b/console/src/components/Indicator/utils.ts
@@ -1,8 +1,8 @@
// @ts-nocheck
+/* eslint-disable */
+import struct from '@aksel/structjs'
-import _ from 'lodash'
-
-interface IRocAuc {
+export interface IRocAuc {
fpr: number[]
tpr: number[]
thresholds: number[]
@@ -70,7 +70,18 @@ const Layout = {
},
}
-export function getRocAucConfig(title = '', labels: string[], data: Record
) {
+var unhexlify = function (str) {
+ const f = new Uint8Array(8)
+ let j = 0
+ for (var i = 0, l = str.length; i < l; i += 2) {
+ f[j] = parseInt(str.substr(i, 2), 16)
+ j++
+ }
+ let s = struct('>d')
+ return s.unpack(f.buffer)[0]
+}
+
+export function getRocAucConfig(title = '', labels: string[], data: IRocAuc[]) {
const layout = {
...Layout.init,
title,
@@ -86,20 +97,29 @@ export function getRocAucConfig(title = '', labels: string[], data: Record {
+ return parseInt(a.id) - parseInt(b.id)
+ })
+ data?.forEach((item, i) => {
+ if (i % 6 != 0) return
+ fpr.push(Number(unhexlify(item.fpr).toFixed('4')))
+ tpr.push(Number(unhexlify(item.tpr).toFixed('4')))
+ })
+
const rocAucData = {
data: [
- ..._.map(data, (roc_auc, label) => {
- return {
- x: roc_auc.fpr,
- y: roc_auc.tpr,
- mode: 'lines+markers',
- name: `label ${label}`,
- type: 'scatter',
- }
- }),
{
- x: [0, 1],
- y: [0, 1],
+ x: fpr,
+ y: tpr,
+ mode: 'lines+markers',
+ name: `label ${0}`,
+ type: 'scatter',
+ },
+ {
+ x: [0.0, 1],
+ y: [0.0, 1],
mode: 'lines',
name: 'baseline',
line: {
@@ -112,6 +132,7 @@ export function getRocAucConfig(title = '', labels: string[], data: Record void
+}
+
+export default function ButtonLink({ children, className, onClick, ...rest }: IButtonLinkProps) {
+ const styles = useLinkStyles()
+
+ return (
+
+ {children}
+
+ )
+}
+// 'row-center--inline', 'gap4',
diff --git a/console/src/components/Link/IconLink.tsx b/console/src/components/Link/IconLink.tsx
new file mode 100644
index 0000000000..865331d2b5
--- /dev/null
+++ b/console/src/components/Link/IconLink.tsx
@@ -0,0 +1,34 @@
+import React from 'react'
+import { createUseStyles } from 'react-jss'
+import cn from 'classnames'
+import BaseLink, { ILinkProps } from './Link'
+
+const useLinkStyles = createUseStyles({
+ link: {
+ 'display': 'flex',
+ 'fontSize': '12px',
+ 'backgroundColor': '#F4F5F7',
+ 'borderRadius': '2px',
+ 'width': '20px',
+ 'height': '20px',
+ 'textDecoration': 'none',
+ 'color': 'gray',
+ '&:hover span': {
+ color: ' #5181E0',
+ },
+ '&:hover': {
+ color: ' #5181E0',
+ backgroundColor: '#F0F4FF',
+ },
+ },
+})
+
+export default function IconLink({ children, className, ...rest }: ILinkProps) {
+ const styles = useLinkStyles()
+
+ return (
+
+ {children}
+
+ )
+}
diff --git a/console/src/components/Link/Link.tsx b/console/src/components/Link/Link.tsx
new file mode 100644
index 0000000000..01748beb62
--- /dev/null
+++ b/console/src/components/Link/Link.tsx
@@ -0,0 +1,39 @@
+import React from 'react'
+import { StatefulTooltip, StatefulTooltipProps } from 'baseui/tooltip'
+import { createUseStyles } from 'react-jss'
+import cn from 'classnames'
+import { Link as BaseLink, LinkProps } from 'react-router-dom'
+
+const useLinkStyles = createUseStyles({
+ link: {
+ 'display': 'flex',
+ 'fontSize': '12px',
+ 'textDecoration': 'none',
+ 'color': 'gray',
+ '&:hover': {
+ color: ' #5181E0',
+ },
+ },
+})
+
+export type ILinkProps = {
+ to: string
+ tooltip?: StatefulTooltipProps
+ children: React.ReactNode
+ style?: React.CSSProperties
+ className?: string
+} & LinkProps
+
+export default function Link({ to, tooltip, className, style = {}, children, ...rest }: ILinkProps) {
+ const styles = useLinkStyles()
+
+ const { content, placement = 'top', ...tooltipRest } = tooltip || {}
+
+ return (
+
+
+ {children}
+
+
+ )
+}
diff --git a/console/src/components/Link/TextLink.tsx b/console/src/components/Link/TextLink.tsx
new file mode 100644
index 0000000000..c41c1b6324
--- /dev/null
+++ b/console/src/components/Link/TextLink.tsx
@@ -0,0 +1,37 @@
+import React from 'react'
+import { createUseStyles } from 'react-jss'
+import cn from 'classnames'
+import BaseLink, { ILinkProps } from './Link'
+
+const useLinkStyles = createUseStyles({
+ link: {
+ // display: 'inline-block',
+ textDecoration: 'none',
+ flex: 1,
+ width: '100%',
+ textOverflow: 'ellipsis',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ },
+ text: {
+ 'display': 'initial',
+ 'fontSize': '14px',
+ 'color': 'rgb(2, 16, 43)',
+ '&:hover': {
+ textDecoration: 'underline',
+ color: ' #5181E0 ',
+ },
+ },
+})
+
+export default function TextLink({ children, className, style, ...rest }: ILinkProps) {
+ const styles = useLinkStyles()
+
+ return (
+
+
+ {children}
+
+
+ )
+}
diff --git a/console/src/components/Link/index.ts b/console/src/components/Link/index.ts
new file mode 100644
index 0000000000..38b8017c7c
--- /dev/null
+++ b/console/src/components/Link/index.ts
@@ -0,0 +1,4 @@
+export * from './Link'
+export { default as IconLink } from './IconLink'
+export { default as TextLink } from './TextLink'
+export { default as ButtonLink } from './ButtonLink'
diff --git a/console/src/components/Table/TableNormal.tsx b/console/src/components/Table/TableNormal.tsx
index f1689db878..773516559d 100644
--- a/console/src/components/Table/TableNormal.tsx
+++ b/console/src/components/Table/TableNormal.tsx
@@ -1,14 +1,11 @@
/* eslint-disable */
-import React, { useRef, useState, useMemo } from 'react'
-import { Table as TableSemantic, TableProps as BaseTableProps } from 'baseui/table-semantic'
+import React, { useRef, useMemo } from 'react'
+import { TableProps as BaseTableProps } from 'baseui/table-semantic'
import { Pagination, SIZE as PaginationSize } from 'baseui/pagination'
import { Skeleton } from 'baseui/skeleton'
-import { FiInbox } from 'react-icons/fi'
import useTranslation from '@/hooks/useTranslation'
-import Text from '@/components/Text'
import { usePage } from '@/hooks/usePage'
import { IPaginationProps } from '@/components/Table/IPaginationProps'
-import { StatefulTooltip } from 'baseui/tooltip'
import {
StatefulDataTable,
CategoricalColumn,
@@ -27,6 +24,7 @@ import type { ColumnT, ConfigT, RowT } from '../data-table/types'
import { useUID, useUIDSeed } from 'react-uid'
import useStore from '../data-table/store'
import { useEffect } from 'react'
+import BusyPlaceholder from '../BusyLoaderWrapper/BusyPlaceholder'
export interface ITableProps extends BaseTableProps {
batchActions?: Types.BatchActionT[]
@@ -254,7 +252,7 @@ export function TableTyped({
gap: 8,
}}
>
-
+
)}
/>
diff --git a/console/src/components/Table/TableTyped.tsx b/console/src/components/Table/TableTyped.tsx
index b7c164adae..1f7d2a26b6 100644
--- a/console/src/components/Table/TableTyped.tsx
+++ b/console/src/components/Table/TableTyped.tsx
@@ -1,14 +1,11 @@
/* eslint-disable */
-import React, { useRef, useState, useMemo } from 'react'
-import { Table as TableSemantic, TableProps as BaseTableProps } from 'baseui/table-semantic'
+import React, { useRef, useMemo } from 'react'
+import { TableProps as BaseTableProps } from 'baseui/table-semantic'
import { Pagination, SIZE as PaginationSize } from 'baseui/pagination'
import { Skeleton } from 'baseui/skeleton'
-import { FiInbox } from 'react-icons/fi'
import useTranslation from '@/hooks/useTranslation'
-import Text from '@/components/Text'
import { usePage } from '@/hooks/usePage'
import { IPaginationProps } from '@/components/Table/IPaginationProps'
-import { StatefulTooltip } from 'baseui/tooltip'
import {
StatefulDataTable,
CategoricalColumn,
@@ -29,6 +26,7 @@ import { useEffect } from 'react'
import { useStyletron } from 'baseui'
import { createUseStyles } from 'react-jss'
import cn from 'classnames'
+import BusyPlaceholder from '../BusyLoaderWrapper/BusyPlaceholder'
const useStyles = createUseStyles({
table: {
@@ -286,23 +284,7 @@ export function TableTyped({
/>
)}
// @ts-ignore
- emptyMessage={() => (
-
-
-
- )}
+ emptyMessage={() =>
}
/>
{paginationProps && (
diff --git a/console/src/components/Table/index.tsx b/console/src/components/Table/index.tsx
index e24524eb00..421508f6f1 100644
--- a/console/src/components/Table/index.tsx
+++ b/console/src/components/Table/index.tsx
@@ -2,18 +2,15 @@ import React from 'react'
import { Table as TableSemantic, TableProps as BaseTableProps } from 'baseui/table-semantic'
import { Pagination, SIZE as PaginationSize } from 'baseui/pagination'
import { Skeleton } from 'baseui/skeleton'
-import { FiInbox } from 'react-icons/fi'
-import useTranslation from '@/hooks/useTranslation'
-import Text from '@/components/Text'
import { usePage } from '@/hooks/usePage'
import { IPaginationProps } from '@/components/Table/IPaginationProps'
+import BusyPlaceholder from '../BusyLoaderWrapper/BusyPlaceholder'
export interface ITableProps extends BaseTableProps {
paginationProps?: IPaginationProps
}
export default function Table({ isLoading, columns, data, overrides, paginationProps }: ITableProps) {
- const [t] = useTranslation()
const [page, setPage] = usePage()
return (
@@ -77,8 +74,7 @@ export default function Table({ isLoading, columns, data, overrides, paginationP
height: 100,
}}
>
-
- {t('no data')}
+
}
/>
diff --git a/console/src/components/data-table/data-custom-table.tsx b/console/src/components/data-table/data-custom-table.tsx
index 9fe703c362..bf82ed4fe5 100644
--- a/console/src/components/data-table/data-custom-table.tsx
+++ b/console/src/components/data-table/data-custom-table.tsx
@@ -228,7 +228,7 @@ const RowPlacementMemo: React.ReactComponentElement = React.memo (c ? c.fillWidth : true)).length
const padding = filledColumnsLen === 0 ? 0 : Math.floor(remainder / filledColumnsLen)
- // console.log(resizedWidths, remainder, padding)
if (padding > 0) {
const result = []
// -1 so that we loop over all but the last item
@@ -1046,6 +1045,7 @@ export function DataTable({
return result
}
}
+
return resizedWidths
}, [
gridRef,
diff --git a/console/src/components/data-table/header-cell.tsx b/console/src/components/data-table/header-cell.tsx
index 3b60ccf4c2..3fa6939e9c 100644
--- a/console/src/components/data-table/header-cell.tsx
+++ b/console/src/components/data-table/header-cell.tsx
@@ -171,7 +171,8 @@ const HeaderCell = React.forwardRef((props, re
position: 'relative',
width: '100%',
display: 'flex',
- alignItems: 'center',
+ alignItems: 'flex-end',
+ flex: 1,
})}
>
{(props.isHovered || props.sortDirection) && props.sortable && (
@@ -256,9 +257,8 @@ const HeaderCell = React.forwardRef((props, re
{/* usesd for popover postion ref */}
+ children: React.ReactNode
+}
+
+// const StoreProvider = ({ key, initState, children }: IStoreProviderProps) => (
+// const storeRef = useRef
>();
+// if (!storeRef.current) {
+// storeRef.current = createMyStore();
+// }
+
+// createCustomStore(key ?? 'store', initState)}>{children}
+// )
+
+// export { StoreProvider, useStore }
+
+const MyContext = createContext(null)
+
+export function StoreProvider({ key = 'store', initState, children }: IStoreProviderProps) {
+ const storeRef = React.useRef()
+ if (!storeRef.current) {
+ storeRef.current = createCustomStore(key, initState)
+ }
+ console.log(storeRef.current)
+ return {children}
+}
+
+export function useContextStore(selector: (state: ITableState) => T) {
+ const store = useContext(MyContext)
+ if (store === null) {
+ throw new Error('Missing Wrapper in the tree')
+ }
+ const value = useStore(store, selector)
+ return value
+}
diff --git a/console/src/domain/datastore/hooks/useParseDatastore.ts b/console/src/domain/datastore/hooks/useParseDatastore.ts
new file mode 100644
index 0000000000..60bdd10fb6
--- /dev/null
+++ b/console/src/domain/datastore/hooks/useParseDatastore.ts
@@ -0,0 +1,41 @@
+// @ts-nocheck
+/* eslint-disable */
+import omit from 'lodash/omit'
+import keyBy from 'lodash/keyBy'
+import React from 'react'
+import { RecordListVO } from '../schemas/datastore'
+import struct from '@aksel/structjs'
+
+const unhexlify = function (str) {
+ const f = new Uint8Array(8)
+ let j = 0
+ for (var i = 0, l = str.length; i < l; i += 2) {
+ f[j] = parseInt(str.substr(i, 2), 16)
+ j++
+ }
+ let s = struct('>d')
+
+ return s.unpack(f.buffer)[0]
+}
+export function useParseConfusionMatrix(data: RecordListVO = {}) {
+ const labels = React.useMemo(() => {
+ const { columnTypes } = data
+ return Object.keys(omit(columnTypes, 'id')).sort()
+ }, [data])
+
+ const binarylabel = React.useMemo(() => {
+ const { records = [] } = data
+ const recordMap = keyBy(records, 'id')
+ const rtn: any[][] = []
+ labels.forEach((labeli, i) => {
+ labels.forEach((labelj, j) => {
+ if (!rtn[i]) rtn[i] = []
+ rtn[i][j] = unhexlify(recordMap?.[labeli.split('_')[1]]?.[labelj]) ?? ''
+ })
+ })
+ return rtn
+ }, [data, labels])
+
+ // console.log(labels, binarylabel)
+ return { labels, binarylabel }
+}
diff --git a/console/src/domain/datastore/utils.ts b/console/src/domain/datastore/utils.ts
index 9d6730be1c..9a06c40054 100644
--- a/console/src/domain/datastore/utils.ts
+++ b/console/src/domain/datastore/utils.ts
@@ -4,8 +4,8 @@ const VERSION_PREFIX_CNT = 2
export function tableDataLink(
projectId: string,
- datasetId: string,
- datasetVersion: string,
+ datasetName: string,
+ datasetVersionName: string,
query: {
uri: string
authName: string
@@ -14,20 +14,33 @@ export function tableDataLink(
Authorization?: string
}
) {
- return `/api/v1/project/${projectId}/dataset/${datasetId}/version/${datasetVersion}/link?${qs.stringify(query)}`
+ return `/api/v1/project/${projectId}/dataset/${datasetName}/version/${datasetVersionName}/link?${qs.stringify(
+ query
+ )}`
}
-export function tableNameOfDataset(projectId: string, datasetId: string, datasetVersion: string) {
- return `project/${projectId}/dataset/${datasetId}/${datasetVersion.substring(
+export function tableNameOfDataset(projectName: string, datasetName: string, datasetVersionName: string) {
+ return `project/${projectName}/dataset/${datasetName}/${datasetVersionName.substring(
0,
VERSION_PREFIX_CNT
- )}/${datasetVersion}/meta`
+ )}/${datasetVersionName}/meta`
}
-export function tableNameOfResult(projectId: string, evaluationId: string) {
- return `project/${projectId}/eval/${evaluationId}/results`
+export function tableNameOfResult(projectName: string, evaluationUuid: string) {
+ return `project/${projectName}/eval/${evaluationUuid.substring(0, VERSION_PREFIX_CNT)}/${evaluationUuid}/results`
}
-export function tableNameOfSummary(projectId: string) {
- return `/project/${projectId}/eval/summary`
+export function tableNameOfConfusionMatrix(projectName: string, evaluationUuid: string) {
+ return `project/${projectName}/eval/${evaluationUuid.substring(
+ 0,
+ VERSION_PREFIX_CNT
+ )}/${evaluationUuid}/confusion_matrix/binarylabel`
+}
+
+export function tableNameOfRocAuc(projectName: string, evaluationUuid: string) {
+ return `project/${projectName}/eval/${evaluationUuid.substring(0, VERSION_PREFIX_CNT)}/${evaluationUuid}/roc_auc/0`
+}
+
+export function tableNameOfSummary(projectName: string) {
+ return `project/${projectName}/eval/summary`
}
diff --git a/console/src/domain/project/hooks/useFetchProject.ts b/console/src/domain/project/hooks/useFetchProject.ts
index 29ffef4aa2..66aa1f26aa 100644
--- a/console/src/domain/project/hooks/useFetchProject.ts
+++ b/console/src/domain/project/hooks/useFetchProject.ts
@@ -3,8 +3,7 @@ import { fetchProject } from '../services/project'
export function useFetchProject(projectId?: string) {
const projectInfo = useQuery(`fetchProject:${projectId}`, () => {
- // eslint-disable-next-line prefer-promise-reject-errors
- if (!projectId) return Promise.reject('fetchProject: no projectId stop fetching')
+ if (!projectId) return Promise.reject(new Error('fetchProject: no projectId stop fetching'))
return fetchProject(projectId)
})
diff --git a/console/src/domain/project/schemas/project.tsx b/console/src/domain/project/schemas/project.tsx
index 3e123572f5..f4767e8d38 100644
--- a/console/src/domain/project/schemas/project.tsx
+++ b/console/src/domain/project/schemas/project.tsx
@@ -6,6 +6,12 @@ export interface IProjectSchema extends IResourceSchema {
owner?: IUserSchema
privacy?: string
description?: string
+ statistics: {
+ modelCounts: number
+ datasetCounts: number
+ evaluationCounts: number
+ memberCounts: number
+ }
}
export interface IUpdateProjectSchema {
diff --git a/console/src/domain/user/schemas/user.tsx b/console/src/domain/user/schemas/user.tsx
index d743690b89..486487d31b 100644
--- a/console/src/domain/user/schemas/user.tsx
+++ b/console/src/domain/user/schemas/user.tsx
@@ -10,6 +10,7 @@ export interface IUserRoleSchema {
export interface IUserSchema extends IResourceSchema {
id: string
name: string
+ email: string
isEnabled: string
role: IUserRoleSchema
}
diff --git a/console/src/i18n/locales.ts b/console/src/i18n/locales.ts
index 6c5cf5936e..cf89139112 100644
--- a/console/src/i18n/locales.ts
+++ b/console/src/i18n/locales.ts
@@ -348,9 +348,6 @@ const locales0 = {
'Password Not Equal': {
en: 'The passwords you entered do not match',
},
- 'no data': {
- en: 'no data',
- },
'submit': {
en: 'submit',
},
@@ -616,6 +613,12 @@ const locales0 = {
'or': {
en: 'or',
},
+ 'Members': {
+ en: 'Members',
+ },
+ 'Signed in as': {
+ en: 'Signed in as',
+ },
}
export const locales: { [key in keyof typeof locales0]: ILocaleItem } = locales0
diff --git a/console/src/main.tsx b/console/src/main.tsx
index 57db783996..435de725e0 100644
--- a/console/src/main.tsx
+++ b/console/src/main.tsx
@@ -4,7 +4,12 @@ import '@/styles/_global.scss'
import '@/i18n'
import reportWebVitals from '@/reportWebVitals'
import App from './App'
-
+// eslint-disable-next-line
+// @ts-ignore
+window.g = null
+// eslint-disable-next-line
+// @ts-ignore
+window.i = null
ReactDOM.render(
diff --git a/console/src/pages/Dataset/DatasetListCard.tsx b/console/src/pages/Dataset/DatasetListCard.tsx
index ab1563539b..84662d4374 100644
--- a/console/src/pages/Dataset/DatasetListCard.tsx
+++ b/console/src/pages/Dataset/DatasetListCard.tsx
@@ -6,13 +6,12 @@ import { ICreateDatasetSchema } from '@dataset/schemas/dataset'
import DatasetForm from '@dataset/components/DatasetForm'
import { formatTimestampDateTime } from '@/utils/datetime'
import useTranslation from '@/hooks/useTranslation'
-// import { Button, SIZE as ButtonSize } from 'baseui/button'
import User from '@/domain/user/components/User'
import { Modal, ModalHeader, ModalBody } from 'baseui/modal'
import Table from '@/components/Table'
-import { Link, useParams } from 'react-router-dom'
+import { useParams } from 'react-router-dom'
import { useFetchDatasets } from '@dataset/hooks/useFetchDatasets'
-// import IconFont from '@/components/IconFont'
+import { TextLink } from '@/components/Link'
export default function DatasetListCard() {
const [page] = usePage()
@@ -31,32 +30,21 @@ export default function DatasetListCard() {
const [t] = useTranslation()
return (
- }
- // size={ButtonSize.compact}
- // onClick={() => setIsCreateDatasetOpen(true)}
- // >
- // {t('create')}
- //
- // }
- >
+
{
return [
-
+
{dataset.name}
- ,
+ ,
dataset.owner && ,
dataset.createdTime && formatTimestampDateTime(dataset.createdTime),
-
+
{t('Version History')}
- ,
+ ,
]
}) ?? []
}
diff --git a/console/src/pages/Dataset/DatasetOverviewLayout.tsx b/console/src/pages/Dataset/DatasetOverviewLayout.tsx
index bccd2a9e44..001f0fc85f 100644
--- a/console/src/pages/Dataset/DatasetOverviewLayout.tsx
+++ b/console/src/pages/Dataset/DatasetOverviewLayout.tsx
@@ -167,9 +167,11 @@ export default function DatasetOverviewLayout({ children }: IDatasetLayoutProps)
style: {
flex: 1,
display: 'flex',
+ fontSize: '14px',
},
},
}}
+ accordion={false}
>
diff --git a/console/src/pages/Dataset/DatasetVersionLayout.tsx b/console/src/pages/Dataset/DatasetVersionLayout.tsx
index 47dc877597..ad4332f82a 100644
--- a/console/src/pages/Dataset/DatasetVersionLayout.tsx
+++ b/console/src/pages/Dataset/DatasetVersionLayout.tsx
@@ -6,7 +6,6 @@ import { useParams } from 'react-router-dom'
import { INavItem } from '@/components/BaseSidebar'
import { fetchDataset } from '@dataset/services/dataset'
import BaseSubLayout from '@/pages/BaseSubLayout'
-import { useFetchProject } from '@/domain/project/hooks/useFetchProject'
export interface IDatasetLayoutProps {
children: React.ReactNode
@@ -16,7 +15,6 @@ export default function DatasetVersionLayout({ children }: IDatasetLayoutProps)
const { projectId, datasetId } = useParams<{ datasetId: string; projectId: string }>()
const datasetInfo = useQuery(`fetchDataset:${projectId}:${datasetId}`, () => fetchDataset(projectId, datasetId))
const { dataset, setDataset } = useDataset()
- const projectInfo = useFetchProject(projectId)
const { setDatasetLoading } = useDatasetLoading()
useEffect(() => {
setDatasetLoading(datasetInfo.isLoading)
@@ -38,25 +36,23 @@ export default function DatasetVersionLayout({ children }: IDatasetLayoutProps)
const [t] = useTranslation()
const datasetName = dataset?.versionName ?? '-'
- const project = projectInfo.data ?? {}
-
const breadcrumbItems: INavItem[] = useMemo(() => {
const items = [
{
title: t('Datasets'),
- path: `/projects/${project?.id}/datasets`,
+ path: `/projects/${projectId}/datasets`,
},
{
title: datasetName,
- path: `/projects/${project?.id}/datasets/${datasetId}`,
+ path: `/projects/${projectId}/datasets/${datasetId}`,
},
{
title: t('dataset versions'),
- path: `/projects/${project?.id}/datasets/${datasetId}/versions`,
+ path: `/projects/${projectId}/datasets/${datasetId}/versions`,
},
]
return items
- }, [project?.id, datasetId, datasetName, t])
+ }, [projectId, datasetId, datasetName, t])
return
{children}
}
diff --git a/console/src/pages/Dataset/DatasetVersionListCard.tsx b/console/src/pages/Dataset/DatasetVersionListCard.tsx
index 3ab5ef5903..e9e3e77ccb 100644
--- a/console/src/pages/Dataset/DatasetVersionListCard.tsx
+++ b/console/src/pages/Dataset/DatasetVersionListCard.tsx
@@ -9,10 +9,10 @@ import useTranslation from '@/hooks/useTranslation'
import User from '@/domain/user/components/User'
import { Modal, ModalHeader, ModalBody } from 'baseui/modal'
import Table from '@/components/Table'
-import { Link, useParams } from 'react-router-dom'
+import { useParams } from 'react-router-dom'
import { useFetchDatasetVersions } from '@dataset/hooks/useFetchDatasetVersions'
-import { StyledLink } from 'baseui/link'
import { toaster } from 'baseui/toast'
+import { ButtonLink, TextLink } from '@/components/Link'
export default function DatasetVersionListCard() {
const [page] = usePage()
@@ -48,35 +48,22 @@ export default function DatasetVersionListCard() {
data={
datasetVersionsInfo.data?.list.map((datasetVersion) => {
return [
-
{datasetVersion.name}
- ,
- //
,
+ ,
datasetVersion.createdTime && formatTimestampDateTime(datasetVersion.createdTime),
datasetVersion.owner &&
,
-
{
handleAction(datasetVersion.id)
}}
>
{t('Revert')}
- ,
+ ,
]
}) ?? []
}
diff --git a/console/src/pages/Evaluation/EvaluationLayout.tsx b/console/src/pages/Evaluation/EvaluationLayout.tsx
index 47ec29dbc0..907da6e4aa 100644
--- a/console/src/pages/Evaluation/EvaluationLayout.tsx
+++ b/console/src/pages/Evaluation/EvaluationLayout.tsx
@@ -6,7 +6,6 @@ import { useParams } from 'react-router-dom'
import { INavItem } from '@/components/BaseSidebar'
import { fetchJob } from '@job/services/job'
import BaseSubLayout from '@/pages/BaseSubLayout'
-import { useFetchProject } from '@/domain/project/hooks/useFetchProject'
export interface IJobLayoutProps {
children: React.ReactNode
@@ -16,7 +15,6 @@ export default function EvaluationLayout({ children }: IJobLayoutProps) {
const { projectId, jobId } = useParams<{ jobId: string; projectId: string }>()
const jobInfo = useQuery(`fetchJob:${projectId}:${jobId}`, () => fetchJob(projectId, jobId))
const { job, setJob } = useJob()
- const projectInfo = useFetchProject(projectId)
const { setJobLoading } = useJobLoading()
useEffect(() => {
setJobLoading(jobInfo.isLoading)
@@ -31,21 +29,20 @@ export default function EvaluationLayout({ children }: IJobLayoutProps) {
const [t] = useTranslation()
const uuid = job?.uuid ?? '-'
- const project = projectInfo.data ?? {}
const breadcrumbItems: INavItem[] = useMemo(() => {
const items = [
{
title: t('Jobs'),
- path: `/projects/${project?.id}/evaluations`,
+ path: `/projects/${projectId}/evaluations`,
},
{
title: uuid ?? '-',
- path: `/projects/${project?.id}/evaluations/${jobId}`,
+ path: `/projects/${projectId}/evaluations/${jobId}`,
},
]
return items
- }, [project?.id, jobId, uuid, t])
+ }, [projectId, jobId, uuid, t])
return
{children}
}
diff --git a/console/src/pages/Evaluation/EvaluationListCard.tsx b/console/src/pages/Evaluation/EvaluationListCard.tsx
index 31876a6fc5..a996cc10e4 100644
--- a/console/src/pages/Evaluation/EvaluationListCard.tsx
+++ b/console/src/pages/Evaluation/EvaluationListCard.tsx
@@ -8,22 +8,22 @@ import useTranslation from '@/hooks/useTranslation'
import { Button, SIZE as ButtonSize } from 'baseui/button'
import { Modal, ModalHeader, ModalBody } from 'baseui/modal'
import Table from '@/components/Table/TableTyped'
-import { Link, useHistory, useParams } from 'react-router-dom'
+import { useHistory, useParams } from 'react-router-dom'
import IconFont from '@/components/IconFont'
import { CustomColumn, StringColumn } from '@/components/data-table'
import { useDrawer } from '@/hooks/useDrawer'
import { useFetchEvaluations } from '@/domain/evaluation/hooks/useFetchEvaluations'
-import { useFetchEvaluationAttrs } from '@/domain/evaluation/hooks/useFetchEvaluationAttrs'
-import { usePage } from '@/hooks/usePage'
import { ColumnT } from '@/components/data-table/types'
-import { IEvaluationAttributeValue } from '@/domain/evaluation/schemas/evaluation'
import _ from 'lodash'
import { useStyletron } from 'baseui'
import { ITableState, useEvaluationCompareStore, useEvaluationStore } from '@/components/data-table/store'
+import { StoreProvider } from '@/components/data-table/storeContext'
import { useFetchViewConfig } from '@/domain/evaluation/hooks/useFetchViewConfig'
import { setEvaluationViewConfig } from '@/domain/evaluation/services/evaluation'
import { useQueryDatasetList } from '@/domain/datastore/hooks/useFetchDatastore'
import { tableNameOfSummary } from '@/domain/datastore/utils'
+import { useProject } from '@/domain/project/hooks/useProject'
+import { TextLink } from '@/components/Link'
import EvaluationListCompare from './EvaluationListCompare'
const gridLayout = [
@@ -40,11 +40,10 @@ export default function EvaluationListCard() {
const { expandedWidth, expanded } = useDrawer()
const [t] = useTranslation()
const history = useHistory()
- const [page] = usePage()
const { projectId } = useParams<{ projectId: string }>()
const evaluationsInfo = useFetchEvaluations(projectId, { pageNum: 1, pageSize: 1000 })
- const evaluationAttrsInfo = useFetchEvaluationAttrs(projectId, page)
const evaluationViewConfig = useFetchViewConfig(projectId, 'evaluation')
+ const { project } = useProject()
const [isCreateJobOpen, setIsCreateJobOpen] = useState(false)
const handleCreateJob = useCallback(
@@ -58,11 +57,13 @@ export default function EvaluationListCard() {
const store = useEvaluationStore()
+ // console.log(useContextStore('eva'))
+
const summaryTableName = React.useMemo(() => {
- return tableNameOfSummary(projectId)
- }, [projectId])
- const summaryTable = useQueryDatasetList(summaryTableName, { pageNum: 1, pageSize: 1000 })
- console.log(summaryTable.data)
+ if (!project?.name) return ''
+ return tableNameOfSummary(project?.name as string)
+ }, [project])
+ const summaryTable = useQueryDatasetList(summaryTableName, { pageNum: 0, pageSize: 1000 })
// TODO
// 1. column key should be equal with eva attr field
@@ -72,17 +73,15 @@ export default function EvaluationListCard() {
CustomColumn({
key: 'uuid',
title: t('Evaluation ID'),
- // filterable: true,
- // renderFilter: () =>
1
,
mapDataToValue: (item: any) => item,
// @ts-ignore
renderCell: (props: any) => {
const item = props.value
return (
-
+
{`${item.modelName}-${item.id}`}
-
+
)
},
}),
@@ -138,30 +137,27 @@ export default function EvaluationListCard() {
const $columnsWithAttrs = useMemo(() => {
const columnsWithAttrs = [...columns]
- evaluationAttrsInfo?.data?.forEach((attr) => {
- if (!attr.name.startsWith('summary/')) {
- return
- }
-
- const name = attr.name.split('/').slice(1).join('/')
+ if (!summaryTable?.data) return columnsWithAttrs
- switch (attr.type) {
- default:
- case 'string':
+ Object.entries(summaryTable?.data?.columnTypes ?? {}).forEach(([name, type]) => {
+ switch (type) {
+ case 'UNKNOWN':
+ case 'BYTES':
+ break
+ case 'STRING':
columnsWithAttrs.push(
StringColumn({
- key: attr.name,
+ key: name,
title: name,
filterType: 'string',
- mapDataToValue: (data: any) => data.attributes?.[attr.name],
+ mapDataToValue: (data: any) => data[name],
})
)
break
- case 'float':
- case 'int':
+ default:
columnsWithAttrs.push(
CustomColumn({
- key: attr.name,
+ key: name,
title: name,
sortable: true,
filterType: 'number',
@@ -176,12 +172,9 @@ export default function EvaluationListCard() {
},
// @ts-ignore
renderCell: (props: any) => {
- // .slice(0, 6)
return
{props?.value}
},
- mapDataToValue: (data: any): string =>
- data.attributes?.find((v: IEvaluationAttributeValue) => v.name === attr.name)?.value ??
- '-',
+ mapDataToValue: (data: any): string => data.attributes?.[name] ?? '-',
})
)
break
@@ -189,7 +182,7 @@ export default function EvaluationListCard() {
})
return columnsWithAttrs
- }, [evaluationAttrsInfo, columns])
+ }, [summaryTable.data, columns])
const [compareRows, setCompareRows] = useState
([])
@@ -209,13 +202,13 @@ export default function EvaluationListCard() {
const $data = useMemo(
() =>
evaluationsInfo.data?.list?.map((raw) => {
- const $attributes = raw.attributes?.filter((item: any) => _.startsWith(item.name, 'summary'))
+ const $attributes = summaryTable.data?.records?.find((item: any) => item.id === raw.id)
return {
...raw,
attributes: $attributes,
}
}) ?? [],
- [evaluationsInfo.data]
+ [evaluationsInfo.data, summaryTable.data]
)
const [gridMode, setGridMode] = useState(1)
@@ -367,17 +360,19 @@ export default function EvaluationListCard() {
}
>
-
+
+
+
setIsCreateJobOpen(false)} closeable animate autoFocus>
{t('create sth', [t('Job')])}
@@ -444,7 +439,7 @@ export default function EvaluationListCard() {
title={t('Compare Evaluations')}
style={{ marginRight: expanded ? expandedWidth : '0', marginBottom: 0 }}
>
-
+
>
)}
diff --git a/console/src/pages/Evaluation/EvaluationListCompare.tsx b/console/src/pages/Evaluation/EvaluationListCompare.tsx
index 2bb95eb778..d591c45fc5 100644
--- a/console/src/pages/Evaluation/EvaluationListCompare.tsx
+++ b/console/src/pages/Evaluation/EvaluationListCompare.tsx
@@ -6,12 +6,12 @@ import Table from '@/components/Table/TableTyped'
import { useParams } from 'react-router-dom'
import { useFetchJobs } from '@job/hooks/useFetchJobs'
import { CustomColumn, StringColumn } from '@/components/data-table'
-import { IEvaluationAttributeValue } from '@/domain/evaluation/schemas/evaluation'
import _ from 'lodash'
import IconFont from '@/components/IconFont'
import { useEvaluationCompareStore } from '@/components/data-table/store'
import { Checkbox } from 'baseui/checkbox'
import { longestCommonSubstring } from '@/utils'
+import { RecordListVO } from '../../domain/datastore/schemas/datastore'
type RowT = {
key: string
@@ -73,24 +73,15 @@ const StringCompareCell = ({ value, comparedValue, renderedValue, data }: CellT<
export default function EvaluationListCompare({
rows = [],
- attrs = [],
+ attrs,
}: {
- attrs: IEvaluationAttributeValue[]
rows: any[]
+ attrs: RecordListVO['columnTypes']
}) {
const [t] = useTranslation()
const [page] = usePage()
const { projectId } = useParams<{ projectId: string }>()
const evaluationsInfo = useFetchJobs(projectId, page)
-
- // const results = useQueries(
- // rows.map((row: any) => ({
- // queryKey: `fetchJobResult:${projectId}:${row.id}`,
- // queryFn: () => fetchJobResult(projectId, row.id),
- // refetchOnWindowFocus: false,
- // }))
- // )
-
const store = useEvaluationCompareStore()
const { comparePinnedKey, compareShowCellChanges, compareShowDiffOnly } = store.compare ?? {}
@@ -123,7 +114,7 @@ export default function EvaluationListCompare({
const row = rows.find((r) => r.id === comparePinnedKey) ?? {}
return {
...row,
- ..._.mapValues(_.keyBy(row.attributes, 'name'), (o) => o.value),
+ ...row.attributes,
}
}, [rows, comparePinnedKey])
@@ -186,27 +177,11 @@ export default function EvaluationListCompare({
const $rowWithAttrs = useMemo(() => {
const rowWithAttrs = [...$rows]
- attrs.forEach((attr) => {
- if (!attr.name.startsWith('summary/')) {
- return
- }
-
- const name = attr.name.split('/').slice(1).join('/')
-
+ Object.entries(attrs ?? {}).forEach(([name]) => {
rowWithAttrs.push({
- key: attr.name,
+ key: name,
title: name,
- values: rows.map((data: any) => {
- const attrIndex = data.attributes?.findIndex(
- (row: IEvaluationAttributeValue) => row.name === attr.name
- )
-
- if (attrIndex >= 0) {
- return data.attributes?.[attrIndex]?.value ?? '-'
- }
-
- return '-'
- }),
+ values: rows.map((data: any) => data.attributes?.[name] ?? '-'),
renderCompare: NumberCompareCell,
})
})
diff --git a/console/src/pages/Evaluation/EvaluationOverviewLayout.tsx b/console/src/pages/Evaluation/EvaluationOverviewLayout.tsx
index 1940ed9508..658d96cb2b 100644
--- a/console/src/pages/Evaluation/EvaluationOverviewLayout.tsx
+++ b/console/src/pages/Evaluation/EvaluationOverviewLayout.tsx
@@ -6,9 +6,10 @@ import { useParams } from 'react-router-dom'
import { INavItem } from '@/components/BaseSidebar'
import { fetchJob } from '@job/services/job'
import BaseSubLayout from '@/pages/BaseSubLayout'
-import Card from '@/components/Card'
import { durationToStr, formatTimestampDateTime } from '@/utils/datetime'
-import IconFont from '../../components/IconFont/index'
+import IconFont from '@/components/IconFont/index'
+import Accordion from '@/components/Accordion'
+import { Panel } from 'baseui/accordion'
export interface IJobLayoutProps {
children: React.ReactNode
@@ -20,14 +21,10 @@ function EvaluationOverviewLayout({ children }: IJobLayoutProps) {
const { job, setJob } = useJob()
const { setJobLoading } = useJobLoading()
- // useEffect(() => {
- // setExpanded(false)
- // }, [setExpanded])
-
useEffect(() => {
setJobLoading(jobInfo.isLoading)
if (jobInfo.isSuccess) {
- if (jobInfo.data.id !== job?.id) {
+ if (jobInfo.data?.id !== job?.id) {
setJob(jobInfo.data)
}
} else if (jobInfo.isLoading) {
@@ -74,93 +71,96 @@ function EvaluationOverviewLayout({ children }: IJobLayoutProps) {
return items
}, [projectId, jobId, t])
- const items = [
- {
- label: t('Evaluation ID'),
- value: job?.id ?? '-',
- },
- {
- label: t('Owner'),
- value: job?.owner?.name ?? '-',
- },
- {
- label: t('Status'),
- value: job?.jobStatus ?? '-',
- },
- {
- label: t('Runtime'),
- value: job?.duration && job?.duration > 0 ? durationToStr(job?.duration) : '-',
- },
- {
- label: t('Created'),
- value: job?.createdTime && formatTimestampDateTime(job.createdTime),
- },
- {
- label: t('End Time'),
- value: job?.stopTime && formatTimestampDateTime(job.stopTime),
- },
- {
- label: t('Device'),
- value: `${job?.device ?? '-'}, ${job?.deviceAmount ?? '-'}`,
- },
- {
- label: t('Model'),
- style: {
- gridColumnStart: 'span 2',
+ const info = React.useMemo(() => {
+ const items = [
+ {
+ label: t('Owner'),
+ value: job?.owner?.name ?? '-',
+ },
+ {
+ label: t('Status'),
+ value: job?.jobStatus ?? '-',
+ },
+ {
+ label: t('Runtime'),
+ value: job?.duration && job?.duration > 0 ? durationToStr(job?.duration) : '-',
+ },
+ {
+ label: t('Created'),
+ value: job?.createdTime && formatTimestampDateTime(job.createdTime),
+ },
+ {
+ label: t('End Time'),
+ value: job?.stopTime && formatTimestampDateTime(job.stopTime),
+ },
+ {
+ label: t('Device'),
+ value: `${job?.device ?? '-'}, ${job?.deviceAmount ?? '-'}`,
+ },
+ {
+ label: t('Model'),
+ style: {
+ gridColumnStart: 'span 2',
+ },
+ value: `${job?.modelName ?? '-'}:${job?.modelVersion ?? '-'}`,
},
- value: `${job?.modelName ?? '-'}:${job?.modelVersion ?? '-'}`,
- },
- {
- label: t('Datasets'),
- style: {
- gridColumnStart: 'span 2',
+ {
+ label: t('Datasets'),
+ style: {
+ gridColumnStart: 'span 2',
+ },
+ value: job?.datasets?.join(', '),
},
- value: job?.datasets?.join(', '),
- },
- {
- label: t('Runtime'),
- style: {
- gridColumnStart: 'span 2',
+ {
+ label: t('Runtime'),
+ style: {
+ gridColumnStart: 'span 2',
+ },
+ value: [job?.runtime?.name ?? '-', job?.runtime?.version?.name ?? '-'].join(':'),
},
- value: [job?.runtime?.name ?? '-', job?.runtime?.version?.name ?? '-'].join(':'),
- },
- ]
+ ]
- const header = (
-
- {items.map((v) => (
-
-
- {v?.label}:
+ return (
+
+ {items.map((v) => (
+
+
+ {v?.label}:
+
+
{v?.value}
-
{v?.value}
-
- ))}
-
+ ))}
+
+ )
+ }, [job, t])
+
+ const header = useMemo(
+ () => (
+
+ ),
+ [job, info, t]
)
+
return (
- {children}
+ {children}
)
}
diff --git a/console/src/pages/Evaluation/EvaluationResults.tsx b/console/src/pages/Evaluation/EvaluationResults.tsx
index bb14e25983..33bca2c0c9 100644
--- a/console/src/pages/Evaluation/EvaluationResults.tsx
+++ b/console/src/pages/Evaluation/EvaluationResults.tsx
@@ -1,26 +1,79 @@
import LabelsIndicator from '@/components/Indicator/LabelsIndicator'
-import React, { useMemo } from 'react'
+import React, { useMemo, useEffect } from 'react'
import { useParams } from 'react-router-dom'
import { useQuery } from 'react-query'
import { fetchJobResult } from '@/domain/job/services/job'
import { ILabels, INDICATORTYPE } from '@/components/Indicator/types.d'
import _ from 'lodash'
-import { getHeatmapConfig, getRocAucConfig } from '@/components/Indicator/utils'
+import { getHeatmapConfig, getRocAucConfig, IRocAuc } from '@/components/Indicator/utils'
import { LabelSmall } from 'baseui/typography'
import Card from '@/components/Card'
import useTranslation from '@/hooks/useTranslation'
import SummaryIndicator from '@/components/Indicator/SummaryIndicator'
import BusyPlaceholder from '@/components/BusyLoaderWrapper/BusyPlaceholder'
+import { tableNameOfConfusionMatrix, tableNameOfRocAuc } from '@/domain/datastore/utils'
+import { useJob } from '@/domain/job/hooks/useJob'
+import { useQueryDatasetList, useScanDatastore } from '@/domain/datastore/hooks/useFetchDatastore'
+import { useProject } from '@/domain/project/hooks/useProject'
+import { useParseConfusionMatrix } from '@/domain/datastore/hooks/useParseDatastore'
const PlotlyVisualizer = React.lazy(
() => import(/* webpackChunkName: "PlotlyVisualizer" */ '../../components/Indicator/PlotlyVisualizer')
)
+function Heatmap({ labels, binarylabel }: any) {
+ const [t] = useTranslation()
+ const heatmapData = getHeatmapConfig(t('Confusion Matrix'), labels, binarylabel)
+ return (
+
+ }>
+
+
+
+ )
+}
+
+function RocAuc({ labels, data }: { labels: any[]; data: IRocAuc[] }) {
+ const [t] = useTranslation()
+ const title = t('Roc Auc')
+ const rocaucData = getRocAucConfig(title, labels, data)
+
+ return (
+
+ }>
+
+
+
+ )
+}
+
function EvaluationResults() {
const { jobId, projectId } = useParams<{ jobId: string; projectId: string }>()
const jobResult = useQuery(`fetchJobResult:${projectId}:${jobId}`, () => fetchJobResult(projectId, jobId), {
refetchOnWindowFocus: false,
})
+ const { project } = useProject()
+ const { job } = useJob()
+ const resultTableName = React.useMemo(() => {
+ if (!project?.name || !job?.uuid) return ''
+ return tableNameOfConfusionMatrix(project?.name as string, job?.uuid)
+ }, [project, job])
+
+ const resultTable = useQueryDatasetList(resultTableName, { pageNum: 0, pageSize: 1000 })
+ // console.log(project?.name, resultTableName, resultTable)
+ const { labels, binarylabel } = useParseConfusionMatrix(resultTable.data)
+
+ const rocAucTable = useScanDatastore({
+ tables: [{ tableName: tableNameOfRocAuc(project?.name as string, job?.uuid ?? '') }],
+ start: 0,
+ limit: 1000,
+ })
+
+ useEffect(() => {
+ if (job?.uuid && project?.name) {
+ rocAucTable.refetch()
+ }
+ }, [project?.name, job?.uuid])
const [t] = useTranslation()
@@ -40,7 +93,7 @@ function EvaluationResults() {
break
}
case INDICATORTYPE.CONFUSION_MATRIX: {
- const heatmapData = getHeatmapConfig(k, _.keys(v?.binarylabel), v?.binarylabel)
+ const heatmapData = getHeatmapConfig(k, labels, v?.binarylabel)
outTitle = t('Confusion Matrix')
children = (
}>
@@ -150,6 +203,9 @@ function EvaluationResults() {
}}
>
{indicators}
+
+ {/* @ts-ignore */}
+
)
diff --git a/console/src/pages/Job/JobDAG.tsx b/console/src/pages/Job/JobDAG.tsx
index 4f23a3dc63..2b617da8a5 100644
--- a/console/src/pages/Job/JobDAG.tsx
+++ b/console/src/pages/Job/JobDAG.tsx
@@ -3,7 +3,6 @@ import { useParams } from 'react-router-dom'
import { useQuery } from 'react-query'
import { fetchJobDAG } from '@/domain/job/services/job'
import _ from 'lodash'
-// import useTranslation from '@/hooks/useTranslation'
import BusyPlaceholder from '@/components/BusyLoaderWrapper/BusyPlaceholder'
import DAG from '@/components/DAG/DAG'
import Card from '../../components/Card/index'
@@ -14,8 +13,6 @@ function JobDAG() {
refetchOnWindowFocus: false,
})
- // const [t] = useTranslation()
-
const nodes = useMemo(() => {
if (!jobDAG.data?.groupingNodes) return []
diff --git a/console/src/pages/Job/JobLayout.tsx b/console/src/pages/Job/JobLayout.tsx
index 0b0bc3fcc3..63371e9885 100644
--- a/console/src/pages/Job/JobLayout.tsx
+++ b/console/src/pages/Job/JobLayout.tsx
@@ -6,7 +6,6 @@ import { useParams } from 'react-router-dom'
import { INavItem } from '@/components/BaseSidebar'
import { fetchJob } from '@job/services/job'
import BaseSubLayout from '@/pages/BaseSubLayout'
-import { useFetchProject } from '@/domain/project/hooks/useFetchProject'
export interface IJobLayoutProps {
children: React.ReactNode
@@ -16,7 +15,6 @@ export default function JobLayout({ children }: IJobLayoutProps) {
const { projectId, jobId } = useParams<{ jobId: string; projectId: string }>()
const jobInfo = useQuery(`fetchJob:${projectId}:${jobId}`, () => fetchJob(projectId, jobId))
const { job, setJob } = useJob()
- const projectInfo = useFetchProject(projectId)
const { setJobLoading } = useJobLoading()
useEffect(() => {
setJobLoading(jobInfo.isLoading)
@@ -31,21 +29,19 @@ export default function JobLayout({ children }: IJobLayoutProps) {
const [t] = useTranslation()
const uuid = job?.uuid ?? '-'
- const project = projectInfo.data ?? {}
-
const breadcrumbItems: INavItem[] = useMemo(() => {
const items = [
{
title: t('Jobs'),
- path: `/projects/${project?.id}/jobs`,
+ path: `/projects/${projectId}/jobs`,
},
{
title: uuid ?? '-',
- path: `/projects/${project?.id}/jobs/${jobId}`,
+ path: `/projects/${projectId}/jobs/${jobId}`,
},
]
return items
- }, [project?.id, jobId, uuid, t])
+ }, [projectId, jobId, uuid, t])
return {children}
}
diff --git a/console/src/pages/Job/JobListCard.tsx b/console/src/pages/Job/JobListCard.tsx
index 19958d5e1e..971156cf46 100644
--- a/console/src/pages/Job/JobListCard.tsx
+++ b/console/src/pages/Job/JobListCard.tsx
@@ -10,11 +10,12 @@ import { Button, SIZE as ButtonSize } from 'baseui/button'
import User from '@/domain/user/components/User'
import { Modal, ModalHeader, ModalBody } from 'baseui/modal'
import Table from '@/components/Table/index'
-import { Link, useHistory, useParams } from 'react-router-dom'
+import { useHistory, useParams } from 'react-router-dom'
import { useFetchJobs } from '@job/hooks/useFetchJobs'
import { StyledLink } from 'baseui/link'
import { toaster } from 'baseui/toast'
import IconFont from '@/components/IconFont'
+import { TextLink } from '@/components/Link'
export default function JobListCard() {
const [t] = useTranslation()
@@ -108,16 +109,16 @@ export default function JobListCard() {
>
),
[JobStatusType.SUCCESS]: (
-
+
{t('View Results')}
-
+
),
}
return [
-
+
{job.uuid}
- ,
+ ,
job.modelName,
job.modelVersion,
job.owner && ,
diff --git a/console/src/pages/Job/JobTasks.tsx b/console/src/pages/Job/JobTasks.tsx
index 07c967deb6..d73fcf6683 100644
--- a/console/src/pages/Job/JobTasks.tsx
+++ b/console/src/pages/Job/JobTasks.tsx
@@ -4,12 +4,12 @@ import { toaster } from 'baseui/toast'
import useTranslation from '@/hooks/useTranslation'
import Card from '@/components/Card'
import { LazyLog } from 'react-lazylog'
-import { Accordion, Panel } from 'baseui/accordion'
+import { Panel } from 'baseui/accordion'
import { fetchTaskOfflineFileLog, fetchTaskOfflineLogFiles } from '@/domain/job/services/task'
import { getToken } from '@/api'
-// import useWebSocket from '@/hooks/useWebSocket'
+import { ITaskSchema, TaskStatusType } from '@/domain/job/schemas/task'
+import Accordion from '@/components/Accordion'
import TaskListCard from './TaskListCard'
-import { ITaskSchema, TaskStatusType } from '../../domain/job/schemas/task'
export interface IScrollProps {
scrollTop: number
@@ -38,7 +38,7 @@ export default function JobTasks() {
const files: Record = {}
data.map(async (v: string) => {
const content = await fetchTaskOfflineFileLog(task?.id, v)
- files[v] = content
+ files[v] = content ?? ''
setCurrentLogFiles({
...files,
})
@@ -176,11 +176,11 @@ export default function JobTasks() {
) : (
()
const modelInfo = useQuery(`fetchModel:${projectId}:${modelId}`, () => fetchModel(projectId, modelId))
const { model, setModel } = useModel()
- const projectInfo = useFetchProject(projectId)
const { setModelLoading } = useModelLoading()
useEffect(() => {
setModelLoading(modelInfo.isLoading)
@@ -31,21 +32,83 @@ export default function ModelLayout({ children }: IModelLayoutProps) {
const [t] = useTranslation()
const modelName = model?.versionMeta ?? '-'
- const project = projectInfo.data ?? {}
-
const breadcrumbItems: INavItem[] = useMemo(() => {
const items = [
{
title: t('Models'),
- path: `/projects/${project?.id}/models`,
+ path: `/projects/${projectId}/models`,
},
{
title: modelName,
- path: `/projects/${project?.id}/models/${modelId}`,
+ path: `/projects/${projectId}/models/${modelId}`,
},
]
return items
- }, [project?.id, modelName, modelId, t])
+ }, [projectId, modelName, modelId, t])
+
+ const items = [
+ {
+ label: t('Version Name'),
+ value: model?.versionName ?? '',
+ },
+ {
+ label: t('Version Meta'),
+ value: model?.versionMeta ?? '',
+ },
+ {
+ label: t('Version Tag'),
+ value: model?.versionTag ?? '',
+ },
+ {
+ label: t('Model ID'),
+ value: model?.id ?? '',
+ },
+ {
+ label: t('Created'),
+ value: model?.createdTime && formatTimestampDateTime(model.createdTime),
+ },
+ ]
+
+ const info = (
+
+ {items.map((v) => (
+
+
+ {v?.label}:
+
+
{v?.value}
+
+ ))}
+
+ )
+
+ const header = React.useMemo(
+ () => (
+
+ ),
+ [model, info, t]
+ )
- return {children}
+ return (
+
+ {children}
+
+ )
}
diff --git a/console/src/pages/Model/ModelListCard.tsx b/console/src/pages/Model/ModelListCard.tsx
index 0f001d0ec0..1229f7ee01 100644
--- a/console/src/pages/Model/ModelListCard.tsx
+++ b/console/src/pages/Model/ModelListCard.tsx
@@ -6,13 +6,12 @@ import { ICreateModelSchema } from '@model/schemas/model'
import ModelForm from '@model/components/ModelForm'
import { formatTimestampDateTime } from '@/utils/datetime'
import useTranslation from '@/hooks/useTranslation'
-// import { Button, SIZE as ButtonSize } from 'baseui/button'
import User from '@/domain/user/components/User'
import { Modal, ModalHeader, ModalBody } from 'baseui/modal'
import Table from '@/components/Table'
-import { Link, useParams } from 'react-router-dom'
+import { useParams } from 'react-router-dom'
import { useFetchModels } from '@model/hooks/useFetchModels'
-// import IconFont from '@/components/IconFont'
+import { TextLink } from '@/components/Link'
export default function ModelListCard() {
const [page] = usePage()
@@ -49,14 +48,14 @@ export default function ModelListCard() {
data={
modelsInfo.data?.list.map((model) => {
return [
-
+
{model.name}
- ,
+ ,
model.owner && ,
model.createdTime && formatTimestampDateTime(model.createdTime),
-
+
{t('Version History')}
- ,
+ ,
]
}) ?? []
}
diff --git a/console/src/pages/Model/ModelVersionLayout.tsx b/console/src/pages/Model/ModelVersionLayout.tsx
index 9ba12c76da..32c2c8ad46 100644
--- a/console/src/pages/Model/ModelVersionLayout.tsx
+++ b/console/src/pages/Model/ModelVersionLayout.tsx
@@ -6,7 +6,6 @@ import { useParams } from 'react-router-dom'
import { INavItem } from '@/components/BaseSidebar'
import { fetchModel } from '@model/services/model'
import BaseSubLayout from '@/pages/BaseSubLayout'
-import { useFetchProject } from '@/domain/project/hooks/useFetchProject'
export interface IModelLayoutProps {
children: React.ReactNode
@@ -16,7 +15,6 @@ export default function ModelVersionLayout({ children }: IModelLayoutProps) {
const { projectId, modelId } = useParams<{ modelId: string; projectId: string }>()
const modelInfo = useQuery(`fetchModel:${projectId}:${modelId}`, () => fetchModel(projectId, modelId))
const { model, setModel } = useModel()
- const projectInfo = useFetchProject(projectId)
const { setModelLoading } = useModelLoading()
useEffect(() => {
setModelLoading(modelInfo.isLoading)
@@ -31,25 +29,24 @@ export default function ModelVersionLayout({ children }: IModelLayoutProps) {
const [t] = useTranslation()
const modelName = model?.versionMeta ?? '-'
- const project = projectInfo.data ?? {}
const breadcrumbItems: INavItem[] = useMemo(() => {
const items = [
{
title: t('Models'),
- path: `/projects/${project?.id}/models`,
+ path: `/projects/${projectId}/models`,
},
{
title: modelName,
- path: `/projects/${project?.id}/models/${modelId}`,
+ path: `/projects/${projectId}/models/${modelId}`,
},
{
title: t('model versions'),
- path: `/projects/${project?.id}/models/${modelId}/versions`,
+ path: `/projects/${projectId}/models/${modelId}/versions`,
},
]
return items
- }, [modelName, t, project?.id, modelId])
+ }, [modelName, t, projectId, modelId])
return {children}
}
diff --git a/console/src/pages/Model/Overview.tsx b/console/src/pages/Model/Overview.tsx
index 1ef010e589..1dcaa4117c 100644
--- a/console/src/pages/Model/Overview.tsx
+++ b/console/src/pages/Model/Overview.tsx
@@ -4,7 +4,6 @@ import useTranslation from '@/hooks/useTranslation'
import { useModel, useModelLoading } from '@model/hooks/useModel'
import Card from '@/components/Card'
import { IModelFileSchema } from '@model/schemas/model'
-import { formatTimestampDateTime } from '@/utils/datetime'
export default function ModelOverview() {
const { model } = useModel()
@@ -12,70 +11,13 @@ export default function ModelOverview() {
const [t] = useTranslation()
- const items = [
- {
- label: t('Version Name'),
- value: model?.versionName ?? '',
- },
- {
- label: t('Version Meta'),
- value: model?.versionMeta ?? '',
- },
- {
- label: t('Version Tag'),
- value: model?.versionTag ?? '',
- },
- {
- label: t('Model ID'),
- value: model?.id ?? '',
- },
- {
- label: t('Created'),
- value: model?.createdTime && formatTimestampDateTime(model.createdTime),
- },
- ]
-
- const info = (
-
- {items.map((v) => (
-
-
- {v?.label}:
-
-
{v?.value}
-
- ))}
-
- )
-
return (
<>
- {info}
-
diff --git a/console/src/pages/Project/Overview.tsx b/console/src/pages/Project/Overview.tsx
index ffa416d59d..a3bc800303 100644
--- a/console/src/pages/Project/Overview.tsx
+++ b/console/src/pages/Project/Overview.tsx
@@ -14,6 +14,7 @@ import { createUseStyles } from 'react-jss'
import { useFetchProjectMembers } from '@/domain/project/hooks/useFetchProjectMembers'
import Button from '@/components/Button/Button'
import { useQuery } from 'react-query'
+import Avatar from '@/components/Avatar'
type IProjectCardProps = {
project: IProjectSchema
@@ -99,9 +100,10 @@ const ProjectCard = ({ project, onEdit }: IProjectCardProps) => {
className={styles.tag}
style={{
color: project?.privacy === 'PRIVATE' ? '#4848B3' : '#00B368',
+ backgroundColor: project?.privacy === 'PRIVATE' ? '#EDEDFF' : '#E6FFF4',
}}
>
- {project.privacy}
+ {project.privacy === 'PRIVATE' ? t('Private') : t('Public')}
@@ -129,10 +131,8 @@ const ProjectCard = ({ project, onEdit }: IProjectCardProps) => {
- {members.data?.map((member) => (
-
- {member.user.name?.substr(0, 2)}
-
+ {members.data?.map((member, i) => (
+
))}
diff --git a/console/src/pages/Project/ProjectListCard.tsx b/console/src/pages/Project/ProjectListCard.tsx
index 66d338386f..84f2d79687 100644
--- a/console/src/pages/Project/ProjectListCard.tsx
+++ b/console/src/pages/Project/ProjectListCard.tsx
@@ -7,7 +7,6 @@ import ProjectForm from '@project/components/ProjectForm'
import useTranslation from '@/hooks/useTranslation'
import { Button, SIZE as ButtonSize } from 'baseui/button'
import { Modal, ModalHeader, ModalBody } from 'baseui/modal'
-import { Link } from 'react-router-dom'
import { useFetchProjects } from '@project/hooks/useFetchProjects'
import IconFont from '@/components/IconFont'
import { useCurrentUser } from '@/hooks/useCurrentUser'
@@ -16,70 +15,105 @@ import { QueryInput } from '@/components/data-table/stateful-data-table'
import cn from 'classnames'
import BusyPlaceholder from '@/components/BusyLoaderWrapper/BusyPlaceholder'
import { StatefulTooltip } from 'baseui/tooltip'
-import { IProjectSchema } from '../../domain/project/schemas/project'
+import { createUseStyles } from 'react-jss'
+import { IProjectSchema } from '@/domain/project/schemas/project'
+import { IconLink, TextLink } from '@/components/Link'
type IProjectCardProps = {
project: IProjectSchema
onEdit?: () => void
}
+const useCardStyles = createUseStyles({
+ card: {
+ 'display': 'flex',
+ 'height': '120px',
+ 'gap': '6px',
+ 'background': '#FFFFFF',
+ 'border': '1px solid #E2E7F0',
+ 'borderRadius': '4px',
+ 'padding': '20px',
+ 'flexDirection': 'column',
+ 'alignItems': 'space-between',
+ 'justifyContent': 'space-between',
+ 'textDecoration': 'none',
+ 'color': ' rgba(2,16,43,0.60)',
+ ':hover': {
+ boxShadow: '0 2px 8px 0 rgba(0,0,0,0.20)',
+ },
+ },
+ row: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ flexGrow: 0,
+ lineHeight: '18px',
+ },
+ rowKey: {
+ color: 'rgba(2,16,43,0.60)',
+ marginRight: '8px',
+ },
+ rowValue: {
+ display: 'flex',
+ alignItems: 'center',
+ color: '#02102B',
+ },
+ rowEnd: {
+ marginLeft: 'auto',
+ },
+ name: {
+ textOverflow: 'ellipsis',
+ display: '-webkit-box',
+ WebkitLineClamp: 1,
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ flexBasis: '80%',
+ },
+ description: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ color: ' rgba(2,16,43,0.60)',
+ },
+ descriptionText: {
+ lineHeight: '12px',
+ fontSize: '12px',
+ whiteSpace: 'normal',
+ display: '-webkit-box',
+ WebkitLineClamp: 2,
+ WebkitBoxOrient: 'vertical',
+ overflow: 'hidden',
+ },
+ statistics: {
+ display: 'flex',
+ justifyContent: 'flex-start',
+ color: ' rgba(2,16,43,0.60)',
+ gap: '12px',
+ },
+ statisticsItem: {
+ display: 'flex',
+ gap: '4px',
+ },
+ tag: {
+ fontSize: '12px',
+ color: '#00B368',
+ backgroundColor: '#E6FFF4',
+ borderRadius: '9px',
+ padding: '3px 10px',
+ },
+})
+
const ProjectCard = ({ project, onEdit }: IProjectCardProps) => {
const [css] = useStyletron()
const [t] = useTranslation()
+ const styles = useCardStyles()
return (
-
-
-
-
+
+
+
+
{[project.owner?.name, project.name].join('/')}
-
-
+
+
{
display: 'flex',
fontSize: '12px',
color: project?.privacy === 'PRIVATE' ? '#4848B3' : '#00B368',
- backgroundColor: '#E6FFF4',
+ backgroundColor: project?.privacy === 'PRIVATE' ? '#EDEDFF' : '#E6FFF4',
borderRadius: '9px',
padding: '3px 10px',
})
)}
>
- {project.privacy?.toLowerCase()}
+ {project.privacy === 'PRIVATE' ? t('Private') : t('Public')}
-
-
- {project.description ?? ''}
+
+
{project.description ?? ''}
}
+ placement='bottom'
+ >
+ {project.description ?? ''}
{
justifyContent: 'space-between',
})}
>
-
+
+
+
+
+ {project?.statistics.evaluationCounts}
+
+
+
+
+
+ {project?.statistics.datasetCounts}
+
+
+
+
+
+ {project?.statistics.modelCounts}
+
+
+
+
+
+ {project?.statistics.memberCounts}
+
+
+
-
-
-
-
-
-
+
+
+
+
diff --git a/console/src/pages/Runtime/RuntimeLayout.tsx b/console/src/pages/Runtime/RuntimeLayout.tsx
index 83bf5b1bc2..e5994eb9a8 100644
--- a/console/src/pages/Runtime/RuntimeLayout.tsx
+++ b/console/src/pages/Runtime/RuntimeLayout.tsx
@@ -6,7 +6,6 @@ import { useParams } from 'react-router-dom'
import { INavItem } from '@/components/BaseSidebar'
import { fetchRuntime } from '@/domain/runtime/services/runtime'
import BaseSubLayout from '@/pages/BaseSubLayout'
-import { useFetchProject } from '@/domain/project/hooks/useFetchProject'
export interface IRuntimeLayoutProps {
children: React.ReactNode
@@ -16,7 +15,6 @@ export default function RuntimeLayout({ children }: IRuntimeLayoutProps) {
const { projectId, runtimeId } = useParams<{ runtimeId: string; projectId: string }>()
const runtimeInfo = useQuery(`fetchRuntime:${projectId}:${runtimeId}`, () => fetchRuntime(projectId, runtimeId))
const { runtime, setRuntime } = useRuntime()
- const projectInfo = useFetchProject(projectId)
const { setRuntimeLoading } = useRuntimeLoading()
useEffect(() => {
setRuntimeLoading(runtimeInfo.isLoading)
@@ -38,21 +36,19 @@ export default function RuntimeLayout({ children }: IRuntimeLayoutProps) {
const [t] = useTranslation()
const runtimeName = runtime?.versionMeta ?? '-'
- const project = projectInfo.data ?? {}
-
const breadcrumbItems: INavItem[] = useMemo(() => {
const items = [
{
title: t('Runtimes'),
- path: `/projects/${project?.id}/runtimes`,
+ path: `/projects/${projectId}/runtimes`,
},
{
title: runtimeName,
- path: `/projects/${project?.id}/runtimes/${runtimeId}`,
+ path: `/projects/${projectId}/runtimes/${runtimeId}`,
},
]
return items
- }, [project?.id, runtimeName, runtimeId, t])
+ }, [projectId, runtimeName, runtimeId, t])
return
{children}
}
diff --git a/console/src/pages/Runtime/RuntimeListCard.tsx b/console/src/pages/Runtime/RuntimeListCard.tsx
index 579b426466..2d7e417070 100644
--- a/console/src/pages/Runtime/RuntimeListCard.tsx
+++ b/console/src/pages/Runtime/RuntimeListCard.tsx
@@ -4,9 +4,10 @@ import { usePage } from '@/hooks/usePage'
import { formatTimestampDateTime } from '@/utils/datetime'
import useTranslation from '@/hooks/useTranslation'
import Table from '@/components/Table'
-import { Link, useParams } from 'react-router-dom'
+import { useParams } from 'react-router-dom'
import { useFetchRuntimes } from '@/domain/runtime/hooks/useFetchRuntimes'
import User from '@/domain/user/components/User'
+import { TextLink } from '@/components/Link'
export default function RuntimeListCard() {
const [page] = usePage()
@@ -24,15 +25,15 @@ export default function RuntimeListCard() {
data={
runtimesInfo.data?.list.map((runtime) => {
return [
-
+
{runtime.name}
- ,
+ ,
runtime.version?.meta ?? '-',
runtime.owner &&
,
runtime.createdTime && formatTimestampDateTime(runtime.createdTime),
-
+
{t('Version History')}
- ,
+ ,
]
}) ?? []
}
diff --git a/console/src/pages/Runtime/RuntimeVersionLayout.tsx b/console/src/pages/Runtime/RuntimeVersionLayout.tsx
index a6a9fb3438..4880dfa633 100644
--- a/console/src/pages/Runtime/RuntimeVersionLayout.tsx
+++ b/console/src/pages/Runtime/RuntimeVersionLayout.tsx
@@ -6,7 +6,6 @@ import { useParams } from 'react-router-dom'
import { INavItem } from '@/components/BaseSidebar'
import { fetchRuntime } from '@/domain/runtime/services/runtime'
import BaseSubLayout from '@/pages/BaseSubLayout'
-import { useFetchProject } from '@/domain/project/hooks/useFetchProject'
export interface IRuntimeLayoutProps {
children: React.ReactNode
@@ -16,7 +15,6 @@ export default function RuntimeVersionLayout({ children }: IRuntimeLayoutProps)
const { projectId, runtimeId } = useParams<{ runtimeId: string; projectId: string }>()
const runtimeInfo = useQuery(`fetchRuntime:${projectId}:${runtimeId}`, () => fetchRuntime(projectId, runtimeId))
const { runtime, setRuntime } = useRuntime()
- const projectInfo = useFetchProject(projectId)
const { setRuntimeLoading } = useRuntimeLoading()
useEffect(() => {
setRuntimeLoading(runtimeInfo.isLoading)
@@ -38,25 +36,24 @@ export default function RuntimeVersionLayout({ children }: IRuntimeLayoutProps)
const [t] = useTranslation()
const runtimeName = runtime?.versionMeta ?? '-'
- const project = projectInfo.data ?? {}
const breadcrumbItems: INavItem[] = useMemo(() => {
const items = [
{
title: t('Runtimes'),
- path: `/projects/${project?.id}/runtimes`,
+ path: `/projects/${projectId}/runtimes`,
},
{
title: runtimeName,
- path: `/projects/${project?.id}/runtimes/${runtimeId}`,
+ path: `/projects/${projectId}/runtimes/${runtimeId}`,
},
{
title: t('runtime versions'),
- path: `/projects/${project?.id}/runtimes/${runtimeId}/versions`,
+ path: `/projects/${projectId}/runtimes/${runtimeId}/versions`,
},
]
return items
- }, [runtimeName, t, project?.id, runtimeId])
+ }, [runtimeName, t, projectId, runtimeId])
return
{children}
}
diff --git a/console/src/routes.tsx b/console/src/routes.tsx
index c172680f18..b99a56563b 100644
--- a/console/src/routes.tsx
+++ b/console/src/routes.tsx
@@ -75,8 +75,8 @@ const Routes = () => {
}>
-
+
@@ -95,189 +95,199 @@ const Routes = () => {
}>
-
-
-
- {/* setting */}
-
-
-
-
-
-
-
-
- {/* project */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {/* setting */}
+
+
+
+
+
+
+
+
+ {/* project */}
+
+
-
-
-
-
-
- {/* evaluation */}
-
-
-
-
-
-
-
-
-
-
- {/* job & task */}
-
-
-
-
-
-
-
-
-
-
- {/* datasets */}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* evaluation */}
+
+
+
+
+
+
+
+
+
+
+ {/* job & task */}
+
+
+
+
+
+
+
+
+
+
+ {/* datasets */}
+
+
+
+
+
+
+
-
-
-
-
-
- {/* runtime */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* model */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* admin */}
-
-
-
-
-
-
-
-
- {/* default */}
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ {/* runtime */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* model */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* admin */}
+
+
+
+
+
+
+
+
+ {/* default */}
+
+
+
+
+
+
+
+
+
+
diff --git a/console/vite.config.ts b/console/vite.config.ts
index cca7e3c05a..0706509afc 100644
--- a/console/vite.config.ts
+++ b/console/vite.config.ts
@@ -40,7 +40,7 @@ export default defineConfig({
},
},
plugins: [
- // eslint(),
+ eslint(),
react({
exclude: /\.stories\.(t|j)sx?$/,
}),